about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs340
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs86
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs6
-rw-r--r--src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr4
-rw-r--r--src/test/ui/associated-types/associated-types-no-suitable-bound.stderr4
-rw-r--r--src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr4
-rw-r--r--src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr8
-rw-r--r--src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr4
-rw-r--r--src/test/ui/associated-types/normalization-debruijn-1.rs36
-rw-r--r--src/test/ui/associated-types/normalization-debruijn-2.rs31
-rw-r--r--src/test/ui/associated-types/normalization-debruijn-3.rs41
-rw-r--r--src/test/ui/associated-types/normalization-generality.rs36
-rw-r--r--src/test/ui/generic-associated-types/issue-76407.rs28
-rw-r--r--src/test/ui/generic-associated-types/issue-76826.rs45
-rw-r--r--src/test/ui/issues/issue-18611.stderr8
-rw-r--r--src/test/ui/issues/issue-20831-debruijn.stderr8
-rw-r--r--src/test/ui/nll/normalization-bounds-error.stderr8
-rw-r--r--src/test/ui/wf/wf-foreign-fn-decl-ret.stderr4
19 files changed, 671 insertions, 33 deletions
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index e089b252607..95ea38d32b6 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -2483,9 +2483,10 @@ impl<'tcx> ty::Instance<'tcx> {
                 // `src/test/ui/polymorphization/normalized_sig_types.rs`), and codegen not keeping
                 // track of a polymorphization `ParamEnv` to allow normalizing later.
                 let mut sig = match *ty.kind() {
-                    ty::FnDef(def_id, substs) => tcx
+                    ty::FnDef(def_id, substs) if tcx.sess.opts.debugging_opts.polymorphize => tcx
                         .normalize_erasing_regions(tcx.param_env(def_id), tcx.fn_sig(def_id))
                         .subst(tcx, substs),
+                    ty::FnDef(def_id, substs) => tcx.fn_sig(def_id).subst(tcx, substs),
                     _ => unreachable!(),
                 };
 
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 0e685205069..98fde3707f7 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -29,6 +29,8 @@ use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
 use rustc_span::symbol::sym;
 
+use std::collections::BTreeMap;
+
 pub use rustc_middle::traits::Reveal;
 
 pub type PolyProjectionObligation<'tcx> = Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>;
@@ -296,6 +298,7 @@ struct AssocTypeNormalizer<'a, 'b, 'tcx> {
     cause: ObligationCause<'tcx>,
     obligations: &'a mut Vec<PredicateObligation<'tcx>>,
     depth: usize,
+    universes: Vec<Option<ty::UniverseIndex>>,
 }
 
 impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
@@ -306,12 +309,18 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> {
         depth: usize,
         obligations: &'a mut Vec<PredicateObligation<'tcx>>,
     ) -> AssocTypeNormalizer<'a, 'b, 'tcx> {
-        AssocTypeNormalizer { selcx, param_env, cause, obligations, depth }
+        AssocTypeNormalizer { selcx, param_env, cause, obligations, depth, universes: vec![] }
     }
 
     fn fold<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
         let value = self.selcx.infcx().resolve_vars_if_possible(value);
 
+        assert!(
+            !value.has_escaping_bound_vars(),
+            "Normalizing {:?} without wrapping in a `Binder`",
+            value
+        );
+
         if !value.has_projections() { value } else { value.fold_with(self) }
     }
 }
@@ -321,6 +330,16 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
         self.selcx.tcx()
     }
 
+    fn fold_binder<T: TypeFoldable<'tcx>>(
+        &mut self,
+        t: ty::Binder<'tcx, T>,
+    ) -> ty::Binder<'tcx, T> {
+        self.universes.push(None);
+        let t = t.super_fold_with(self);
+        self.universes.pop();
+        t
+    }
+
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
         if !ty.has_projections() {
             return ty;
@@ -396,6 +415,52 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
                 normalized_ty
             }
 
+            ty::Projection(data) if !data.trait_ref(self.tcx()).has_escaping_bound_vars() => {
+                // Okay, so you thought the previous branch was hacky. Well, to
+                // extend upon this, when the *trait ref* doesn't have escaping
+                // bound vars, but the associated item *does* (can only occur
+                // with GATs), then we might still be able to project the type.
+                // For this, we temporarily replace the bound vars with
+                // placeholders. Note though, that in the case that we still
+                // can't project for whatever reason (e.g. self type isn't
+                // known enough), we *can't* register an obligation and return
+                // an inference variable (since then that obligation would have
+                // bound vars and that's a can of worms). Instead, we just
+                // give up and fall back to pretending like we never tried!
+
+                let infcx = self.selcx.infcx();
+                let (data, mapped_regions, mapped_types, mapped_consts) =
+                    BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
+                let normalized_ty = opt_normalize_projection_type(
+                    self.selcx,
+                    self.param_env,
+                    data,
+                    self.cause.clone(),
+                    self.depth,
+                    &mut self.obligations,
+                )
+                .ok()
+                .flatten()
+                .unwrap_or_else(|| ty);
+
+                let normalized_ty = PlaceholderReplacer::replace_placeholders(
+                    infcx,
+                    mapped_regions,
+                    mapped_types,
+                    mapped_consts,
+                    &self.universes,
+                    normalized_ty,
+                );
+                debug!(
+                    ?self.depth,
+                    ?ty,
+                    ?normalized_ty,
+                    obligations.len = ?self.obligations.len(),
+                    "AssocTypeNormalizer: normalized type"
+                );
+                normalized_ty
+            }
+
             _ => ty,
         }
     }
@@ -410,6 +475,279 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
     }
 }
 
+pub struct BoundVarReplacer<'me, 'tcx> {
+    infcx: &'me InferCtxt<'me, 'tcx>,
+    // These three maps track the bound variable that were replaced by placeholders. It might be
+    // nice to remove these since we already have the `kind` in the placeholder; we really just need
+    // the `var` (but we *could* bring that into scope if we were to track them as we pass them).
+    mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
+    mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>,
+    mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
+    // The current depth relative to *this* folding, *not* the entire normalization. In other words,
+    // the depth of binders we've passed here.
+    current_index: ty::DebruijnIndex,
+    // The `UniverseIndex` of the binding levels above us. These are optional, since we are lazy:
+    // we don't actually create a universe until we see a bound var we have to replace.
+    universe_indices: &'me mut Vec<Option<ty::UniverseIndex>>,
+}
+
+impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> {
+    /// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that
+    /// use a binding level above `universe_indices.len()`, we fail.
+    pub fn replace_bound_vars<T: TypeFoldable<'tcx>>(
+        infcx: &'me InferCtxt<'me, 'tcx>,
+        universe_indices: &'me mut Vec<Option<ty::UniverseIndex>>,
+        value: T,
+    ) -> (
+        T,
+        BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
+        BTreeMap<ty::PlaceholderType, ty::BoundTy>,
+        BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
+    ) {
+        let mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion> = BTreeMap::new();
+        let mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy> = BTreeMap::new();
+        let mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar> = BTreeMap::new();
+
+        let mut replacer = BoundVarReplacer {
+            infcx,
+            mapped_regions,
+            mapped_types,
+            mapped_consts,
+            current_index: ty::INNERMOST,
+            universe_indices,
+        };
+
+        let value = value.super_fold_with(&mut replacer);
+
+        (value, replacer.mapped_regions, replacer.mapped_types, replacer.mapped_consts)
+    }
+
+    fn universe_for(&mut self, debruijn: ty::DebruijnIndex) -> ty::UniverseIndex {
+        let infcx = self.infcx;
+        let index =
+            self.universe_indices.len() - debruijn.as_usize() + self.current_index.as_usize() - 1;
+        let universe = self.universe_indices[index].unwrap_or_else(|| {
+            for i in self.universe_indices.iter_mut().take(index + 1) {
+                *i = i.or_else(|| Some(infcx.create_next_universe()))
+            }
+            self.universe_indices[index].unwrap()
+        });
+        universe
+    }
+}
+
+impl TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> {
+    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+        self.infcx.tcx
+    }
+
+    fn fold_binder<T: TypeFoldable<'tcx>>(
+        &mut self,
+        t: ty::Binder<'tcx, T>,
+    ) -> ty::Binder<'tcx, T> {
+        self.current_index.shift_in(1);
+        let t = t.super_fold_with(self);
+        self.current_index.shift_out(1);
+        t
+    }
+
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+        match *r {
+            ty::ReLateBound(debruijn, _)
+                if debruijn.as_usize() + 1
+                    > self.current_index.as_usize() + self.universe_indices.len() =>
+            {
+                bug!("Bound vars outside of `self.universe_indices`");
+            }
+            ty::ReLateBound(debruijn, br) if debruijn >= self.current_index => {
+                let universe = self.universe_for(debruijn);
+                let p = ty::PlaceholderRegion { universe, name: br.kind };
+                self.mapped_regions.insert(p.clone(), br);
+                self.infcx.tcx.mk_region(ty::RePlaceholder(p))
+            }
+            _ => r,
+        }
+    }
+
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+        match *t.kind() {
+            ty::Bound(debruijn, _)
+                if debruijn.as_usize() + 1
+                    > self.current_index.as_usize() + self.universe_indices.len() =>
+            {
+                bug!("Bound vars outside of `self.universe_indices`");
+            }
+            ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => {
+                let universe = self.universe_for(debruijn);
+                let p = ty::PlaceholderType { universe, name: bound_ty.var };
+                self.mapped_types.insert(p.clone(), bound_ty);
+                self.infcx.tcx.mk_ty(ty::Placeholder(p))
+            }
+            _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self),
+            _ => t,
+        }
+    }
+
+    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+        match *ct {
+            ty::Const { val: ty::ConstKind::Bound(debruijn, _), ty: _ }
+                if debruijn.as_usize() + 1
+                    > self.current_index.as_usize() + self.universe_indices.len() =>
+            {
+                bug!("Bound vars outside of `self.universe_indices`");
+            }
+            ty::Const { val: ty::ConstKind::Bound(debruijn, bound_const), ty }
+                if debruijn >= self.current_index =>
+            {
+                let universe = self.universe_for(debruijn);
+                let p = ty::PlaceholderConst {
+                    universe,
+                    name: ty::BoundConst { var: bound_const, ty },
+                };
+                self.mapped_consts.insert(p.clone(), bound_const);
+                self.infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Placeholder(p), ty })
+            }
+            _ if ct.has_vars_bound_at_or_above(self.current_index) => ct.super_fold_with(self),
+            _ => ct,
+        }
+    }
+}
+
+// The inverse of `BoundVarReplacer`: replaces placeholders with the bound vars from which they came.
+pub struct PlaceholderReplacer<'me, 'tcx> {
+    infcx: &'me InferCtxt<'me, 'tcx>,
+    mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
+    mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>,
+    mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
+    universe_indices: &'me Vec<Option<ty::UniverseIndex>>,
+    current_index: ty::DebruijnIndex,
+}
+
+impl<'me, 'tcx> PlaceholderReplacer<'me, 'tcx> {
+    pub fn replace_placeholders<T: TypeFoldable<'tcx>>(
+        infcx: &'me InferCtxt<'me, 'tcx>,
+        mapped_regions: BTreeMap<ty::PlaceholderRegion, ty::BoundRegion>,
+        mapped_types: BTreeMap<ty::PlaceholderType, ty::BoundTy>,
+        mapped_consts: BTreeMap<ty::PlaceholderConst<'tcx>, ty::BoundVar>,
+        universe_indices: &'me Vec<Option<ty::UniverseIndex>>,
+        value: T,
+    ) -> T {
+        let mut replacer = PlaceholderReplacer {
+            infcx,
+            mapped_regions,
+            mapped_types,
+            mapped_consts,
+            universe_indices,
+            current_index: ty::INNERMOST,
+        };
+        value.super_fold_with(&mut replacer)
+    }
+}
+
+impl TypeFolder<'tcx> for PlaceholderReplacer<'_, 'tcx> {
+    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+        self.infcx.tcx
+    }
+
+    fn fold_binder<T: TypeFoldable<'tcx>>(
+        &mut self,
+        t: ty::Binder<'tcx, T>,
+    ) -> ty::Binder<'tcx, T> {
+        if !t.has_placeholders() && !t.has_infer_regions() {
+            return t;
+        }
+        self.current_index.shift_in(1);
+        let t = t.super_fold_with(self);
+        self.current_index.shift_out(1);
+        t
+    }
+
+    fn fold_region(&mut self, r0: ty::Region<'tcx>) -> ty::Region<'tcx> {
+        let r1 = match r0 {
+            ty::ReVar(_) => self
+                .infcx
+                .inner
+                .borrow_mut()
+                .unwrap_region_constraints()
+                .opportunistic_resolve_region(self.infcx.tcx, r0),
+            _ => r0,
+        };
+
+        let r2 = match *r1 {
+            ty::RePlaceholder(p) => {
+                let replace_var = self.mapped_regions.get(&p);
+                match replace_var {
+                    Some(replace_var) => {
+                        let index = self
+                            .universe_indices
+                            .iter()
+                            .position(|u| matches!(u, Some(pu) if *pu == p.universe))
+                            .unwrap_or_else(|| bug!("Unexpected placeholder universe."));
+                        let db = ty::DebruijnIndex::from_usize(
+                            self.universe_indices.len() - index + self.current_index.as_usize() - 1,
+                        );
+                        self.tcx().mk_region(ty::ReLateBound(db, *replace_var))
+                    }
+                    None => r1,
+                }
+            }
+            _ => r1,
+        };
+
+        debug!(?r0, ?r1, ?r2, "fold_region");
+
+        r2
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        match *ty.kind() {
+            ty::Placeholder(p) => {
+                let replace_var = self.mapped_types.get(&p);
+                match replace_var {
+                    Some(replace_var) => {
+                        let index = self
+                            .universe_indices
+                            .iter()
+                            .position(|u| matches!(u, Some(pu) if *pu == p.universe))
+                            .unwrap_or_else(|| bug!("Unexpected placeholder universe."));
+                        let db = ty::DebruijnIndex::from_usize(
+                            self.universe_indices.len() - index + self.current_index.as_usize() - 1,
+                        );
+                        self.tcx().mk_ty(ty::Bound(db, *replace_var))
+                    }
+                    None => ty,
+                }
+            }
+
+            _ if ty.has_placeholders() || ty.has_infer_regions() => ty.super_fold_with(self),
+            _ => ty,
+        }
+    }
+
+    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+        if let ty::Const { val: ty::ConstKind::Placeholder(p), ty } = *ct {
+            let replace_var = self.mapped_consts.get(&p);
+            match replace_var {
+                Some(replace_var) => {
+                    let index = self
+                        .universe_indices
+                        .iter()
+                        .position(|u| matches!(u, Some(pu) if *pu == p.universe))
+                        .unwrap_or_else(|| bug!("Unexpected placeholder universe."));
+                    let db = ty::DebruijnIndex::from_usize(
+                        self.universe_indices.len() - index + self.current_index.as_usize() - 1,
+                    );
+                    self.tcx()
+                        .mk_const(ty::Const { val: ty::ConstKind::Bound(db, *replace_var), ty })
+                }
+                None => ct,
+            }
+        } else {
+            ct.super_fold_with(self)
+        }
+    }
+}
+
 /// The guts of `normalize`: normalize a specific projection like `<T
 /// as Trait>::Item`. The result is always a type (and possibly
 /// additional obligations). If ambiguity arises, which implies that
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 6673e021bf3..94539eda0f8 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -61,6 +61,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
             error: false,
             cache: SsoHashMap::new(),
             anon_depth: 0,
+            universes: vec![],
         };
 
         let result = value.fold_with(&mut normalizer);
@@ -91,6 +92,7 @@ struct QueryNormalizer<'cx, 'tcx> {
     cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
     error: bool,
     anon_depth: usize,
+    universes: Vec<Option<ty::UniverseIndex>>,
 }
 
 impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
@@ -98,6 +100,16 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
         self.infcx.tcx
     }
 
+    fn fold_binder<T: TypeFoldable<'tcx>>(
+        &mut self,
+        t: ty::Binder<'tcx, T>,
+    ) -> ty::Binder<'tcx, T> {
+        self.universes.push(None);
+        let t = t.super_fold_with(self);
+        self.universes.pop();
+        t
+    }
+
     #[instrument(level = "debug", skip(self))]
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
         if !ty.has_projections() {
@@ -204,6 +216,80 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                     }
                 }
             }
+            ty::Projection(data) if !data.trait_ref(self.infcx.tcx).has_escaping_bound_vars() => {
+                // See note in `rustc_trait_selection::traits::project`
+
+                // One other point mentioning: In `traits::project`, if a
+                // projection can't be normalized, we return an inference variable
+                // and register an obligation to later resolve that. Here, the query
+                // will just return ambiguity. In both cases, the effect is the same: we only want
+                // to return `ty` because there are bound vars that we aren't yet handling in a more
+                // complete way.
+
+                // `BoundVarReplacer` can't handle escaping bound vars. Ideally, we want this before even calling
+                // `QueryNormalizer`, but some const-generics tests pass escaping bound vars.
+                // Also, use `ty` so we get that sweet `outer_exclusive_binder` optimization
+                assert!(!ty.has_vars_bound_at_or_above(ty::DebruijnIndex::from_usize(
+                    self.universes.len()
+                )));
+
+                let tcx = self.infcx.tcx;
+                let infcx = self.infcx;
+                let (data, mapped_regions, mapped_types, mapped_consts) =
+                    crate::traits::project::BoundVarReplacer::replace_bound_vars(
+                        infcx,
+                        &mut self.universes,
+                        data,
+                    );
+                let data = data.super_fold_with(self);
+
+                let mut orig_values = OriginalQueryValues::default();
+                // HACK(matthewjasper) `'static` is special-cased in selection,
+                // so we cannot canonicalize it.
+                let c_data = self
+                    .infcx
+                    .canonicalize_hr_query_hack(self.param_env.and(data), &mut orig_values);
+                debug!("QueryNormalizer: c_data = {:#?}", c_data);
+                debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
+                let normalized_ty = match tcx.normalize_projection_ty(c_data) {
+                    Ok(result) => {
+                        // We don't expect ambiguity.
+                        if result.is_ambiguous() {
+                            self.error = true;
+                            return ty;
+                        }
+                        match self.infcx.instantiate_query_response_and_region_obligations(
+                            self.cause,
+                            self.param_env,
+                            &orig_values,
+                            result,
+                        ) {
+                            Ok(InferOk { value: result, obligations }) => {
+                                debug!("QueryNormalizer: result = {:#?}", result);
+                                debug!("QueryNormalizer: obligations = {:#?}", obligations);
+                                self.obligations.extend(obligations);
+                                result.normalized_ty
+                            }
+                            Err(_) => {
+                                self.error = true;
+                                ty
+                            }
+                        }
+                    }
+                    Err(NoSolution) => {
+                        self.error = true;
+                        ty
+                    }
+                };
+                crate::traits::project::PlaceholderReplacer::replace_placeholders(
+                    infcx,
+                    mapped_regions,
+                    mapped_types,
+                    mapped_consts,
+                    &self.universes,
+                    normalized_ty,
+                )
+            }
 
             _ => ty,
         })();
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 4838d70a831..26d3cc9d891 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -406,7 +406,6 @@ fn check_associated_item(
             }
             ty::AssocKind::Fn => {
                 let sig = fcx.tcx.fn_sig(item.def_id);
-                let sig = fcx.normalize_associated_types_in(span, sig);
                 let hir_sig = sig_if_method.expect("bad signature for method");
                 check_fn_or_method(
                     fcx,
@@ -611,7 +610,6 @@ fn check_item_fn(
     for_id(tcx, item_id, span).with_fcx(|fcx| {
         let def_id = tcx.hir().local_def_id(item_id);
         let sig = tcx.fn_sig(def_id);
-        let sig = fcx.normalize_associated_types_in(span, sig);
         let mut implied_bounds = vec![];
         check_fn_or_method(fcx, ident.span, sig, decl, def_id.to_def_id(), &mut implied_bounds);
         implied_bounds
@@ -898,8 +896,8 @@ fn check_fn_or_method<'fcx, 'tcx>(
     def_id: DefId,
     implied_bounds: &mut Vec<Ty<'tcx>>,
 ) {
-    let sig = fcx.normalize_associated_types_in(span, sig);
     let sig = fcx.tcx.liberate_late_bound_regions(def_id, sig);
+    let sig = fcx.normalize_associated_types_in(span, sig);
 
     for (&input_ty, ty) in iter::zip(sig.inputs(), hir_decl.inputs) {
         fcx.register_wf_obligation(input_ty.into(), ty.span, ObligationCauseCode::MiscObligation);
@@ -1077,8 +1075,8 @@ fn check_method_receiver<'fcx, 'tcx>(
     let span = fn_sig.decl.inputs[0].span;
 
     let sig = fcx.tcx.fn_sig(method.def_id);
-    let sig = fcx.normalize_associated_types_in(span, sig);
     let sig = fcx.tcx.liberate_late_bound_regions(method.def_id, sig);
+    let sig = fcx.normalize_associated_types_in(span, sig);
 
     debug!("check_method_receiver: sig={:?}", sig);
 
diff --git a/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr b/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr
index 6d7289bd071..e8c11a32bf7 100644
--- a/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr
+++ b/src/test/ui/associated-types/associated-types-for-unimpl-trait.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `Self: Get` is not satisfied
-  --> $DIR/associated-types-for-unimpl-trait.rs:10:5
+  --> $DIR/associated-types-for-unimpl-trait.rs:10:8
    |
 LL |     fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
+   |        ^^^^ the trait `Get` is not implemented for `Self`
    |
 help: consider further restricting `Self`
    |
diff --git a/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr b/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr
index 0b5dee611e4..e3be434698a 100644
--- a/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr
+++ b/src/test/ui/associated-types/associated-types-no-suitable-bound.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `T: Get` is not satisfied
-  --> $DIR/associated-types-no-suitable-bound.rs:11:5
+  --> $DIR/associated-types-no-suitable-bound.rs:11:8
    |
 LL |     fn uhoh<T>(foo: <T as Get>::Value) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `T`
+   |        ^^^^ the trait `Get` is not implemented for `T`
    |
 help: consider restricting type parameter `T`
    |
diff --git a/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr b/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr
index dfe62aa5d6b..9dc3414e9ed 100644
--- a/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr
+++ b/src/test/ui/associated-types/associated-types-no-suitable-supertrait-2.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `Self: Get` is not satisfied
-  --> $DIR/associated-types-no-suitable-supertrait-2.rs:17:5
+  --> $DIR/associated-types-no-suitable-supertrait-2.rs:17:8
    |
 LL |     fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
+   |        ^^^^ the trait `Get` is not implemented for `Self`
    |
 help: consider further restricting `Self`
    |
diff --git a/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr b/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr
index f0f2451a1ec..c2aed3f9de5 100644
--- a/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr
+++ b/src/test/ui/associated-types/associated-types-no-suitable-supertrait.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `Self: Get` is not satisfied
-  --> $DIR/associated-types-no-suitable-supertrait.rs:17:5
+  --> $DIR/associated-types-no-suitable-supertrait.rs:17:8
    |
 LL |     fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
+   |        ^^^^ the trait `Get` is not implemented for `Self`
    |
 help: consider further restricting `Self`
    |
@@ -10,10 +10,10 @@ LL |     fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Ge
    |                                                              ^^^^^^^^^^^^^^^
 
 error[E0277]: the trait bound `(T, U): Get` is not satisfied
-  --> $DIR/associated-types-no-suitable-supertrait.rs:22:5
+  --> $DIR/associated-types-no-suitable-supertrait.rs:22:8
    |
 LL |     fn uhoh<U:Get>(&self, foo: U, bar: <(T, U) as Get>::Value) {}
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `(T, U)`
+   |        ^^^^ the trait `Get` is not implemented for `(T, U)`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr
index 4528f03c54a..fb842d96867 100644
--- a/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr
+++ b/src/test/ui/associated-types/associated-types-projection-to-unrelated-trait-in-method-without-default.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `Self: Get` is not satisfied
-  --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:5
+  --> $DIR/associated-types-projection-to-unrelated-trait-in-method-without-default.rs:10:8
    |
 LL |     fn okay<U:Get>(&self, foo: U, bar: <Self as Get>::Value);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Get` is not implemented for `Self`
+   |        ^^^^ the trait `Get` is not implemented for `Self`
    |
 help: consider further restricting `Self`
    |
diff --git a/src/test/ui/associated-types/normalization-debruijn-1.rs b/src/test/ui/associated-types/normalization-debruijn-1.rs
new file mode 100644
index 00000000000..a5abf1ba99d
--- /dev/null
+++ b/src/test/ui/associated-types/normalization-debruijn-1.rs
@@ -0,0 +1,36 @@
+// build-pass
+// edition:2018
+
+// Regression test to ensure we handle debruijn indices correctly in projection
+// normalization under binders. Found in crater run for #85499
+
+use std::future::Future;
+use std::pin::Pin;
+pub enum Outcome<S, E> {
+    Success((S, E)),
+}
+pub struct Request<'r> {
+    _marker: std::marker::PhantomData<&'r ()>,
+}
+pub trait FromRequest<'r>: Sized {
+    type Error;
+    fn from_request<'life0>(
+        request: &'r Request<'life0>,
+    ) -> Pin<Box<dyn Future<Output = Outcome<Self, Self::Error>>>>;
+}
+impl<'r, T: FromRequest<'r>> FromRequest<'r> for Option<T> {
+    type Error = ();
+    fn from_request<'life0>(
+        request: &'r Request<'life0>,
+    ) -> Pin<Box<dyn Future<Output = Outcome<Self, Self::Error>>>> {
+        Box::pin(async move {
+            let request = request;
+            match T::from_request(request).await {
+                _ => todo!(),
+            }
+        });
+        todo!()
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-types/normalization-debruijn-2.rs b/src/test/ui/associated-types/normalization-debruijn-2.rs
new file mode 100644
index 00000000000..abe248e16a1
--- /dev/null
+++ b/src/test/ui/associated-types/normalization-debruijn-2.rs
@@ -0,0 +1,31 @@
+// build-pass
+// edition:2018
+
+// Regression test to ensure we handle debruijn indices correctly in projection
+// normalization under binders. Found in crater run for #85499
+
+use std::future::Future;
+use std::pin::Pin;
+pub enum Outcome<S, E> {
+    Success(S),
+    Failure(E),
+}
+pub struct Request<'r> {
+    _marker: std::marker::PhantomData<&'r ()>,
+}
+pub trait FromRequest<'r>: Sized {
+    type Error;
+    fn from_request<'life0>(
+        request: &'r Request<'life0>,
+    ) -> Pin<Box<dyn Future<Output = Outcome<Self, Self::Error>>>>;
+}
+pub struct S<T> {
+    _marker: std::marker::PhantomData<T>,
+}
+impl<'r, T: FromRequest<'r>> S<T> {
+    pub async fn from_request(request: &'r Request<'_>) {
+        let _ = T::from_request(request).await;
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-types/normalization-debruijn-3.rs b/src/test/ui/associated-types/normalization-debruijn-3.rs
new file mode 100644
index 00000000000..2bea78cf7bd
--- /dev/null
+++ b/src/test/ui/associated-types/normalization-debruijn-3.rs
@@ -0,0 +1,41 @@
+// build-pass
+// edition:2018
+
+// Regression test to ensure we handle debruijn indices correctly in projection
+// normalization under binders. Found in crater run for #85499
+
+use std::future::{Future, Ready};
+async fn read() {
+    let _ = connect(&()).await;
+}
+async fn connect<A: ToSocketAddr>(addr: A) {
+    let _ = addr.to_socket_addr().await;
+}
+pub trait ToSocketAddr {
+    type Future: Future<Output = ()>;
+    fn to_socket_addr(&self) -> Self::Future;
+}
+impl ToSocketAddr for &() {
+    type Future = Ready<()>;
+    fn to_socket_addr(&self) -> Self::Future {
+        unimplemented!()
+    }
+}
+struct Server;
+impl Server {
+    fn and_then<F>(self, _fun: F) -> AndThen<F> {
+        unimplemented!()
+    }
+}
+struct AndThen<F> {
+    _marker: std::marker::PhantomData<F>,
+}
+pub async fn run<F>(_: F) {
+}
+fn main() {
+    let _ = async {
+        let server = Server;
+        let verification_route = server.and_then(read);
+        run(verification_route).await;
+    };
+}
diff --git a/src/test/ui/associated-types/normalization-generality.rs b/src/test/ui/associated-types/normalization-generality.rs
new file mode 100644
index 00000000000..f8e3f5b58d1
--- /dev/null
+++ b/src/test/ui/associated-types/normalization-generality.rs
@@ -0,0 +1,36 @@
+// build-pass
+
+// Ensures that we don't regress on "implementation is not general enough" when
+// normalizating under binders.
+
+#![feature(no_core)]
+
+pub trait Yokeable<'a> {
+    type Output: 'a;
+}
+
+pub struct Yoke<Y: for<'a> Yokeable<'a>> {
+    _yokeable: Y,
+}
+
+impl<Y: for<'a> Yokeable<'a>> Yoke<Y> {
+    pub fn project<'this, P>(
+        &'this self,
+        _f: for<'a> fn(<Y as Yokeable<'a>>::Output, &'a ()) -> <P as Yokeable<'a>>::Output,
+    ) -> Yoke<P>
+    where
+        P: for<'a> Yokeable<'a>,
+    {
+        unimplemented!()
+    }
+}
+
+pub fn slice(y: Yoke<&'static ()>) -> Yoke<&'static ()> {
+    y.project(move |yk, _| yk)
+}
+
+impl<'a, T> Yokeable<'a> for &'static T {
+    type Output = &'a T;
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-76407.rs b/src/test/ui/generic-associated-types/issue-76407.rs
new file mode 100644
index 00000000000..42f19feb5f1
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-76407.rs
@@ -0,0 +1,28 @@
+// check-pass
+
+#![feature(generic_associated_types)]
+#![allow(incomplete_features)]
+
+trait Marker {}
+
+impl Marker for u32 {}
+
+trait MyTrait {
+    type Item<'a>;
+}
+
+struct MyStruct;
+
+impl MyTrait for MyStruct {
+    type Item<'a> = u32;
+}
+
+fn ty_check<T>()
+where
+    T: MyTrait,
+    for<'a> T::Item<'a>: Marker
+{}
+
+fn main() {
+    ty_check::<MyStruct>();
+}
diff --git a/src/test/ui/generic-associated-types/issue-76826.rs b/src/test/ui/generic-associated-types/issue-76826.rs
new file mode 100644
index 00000000000..a905ef4eb13
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-76826.rs
@@ -0,0 +1,45 @@
+// run-pass
+
+#![feature(generic_associated_types)]
+#![allow(incomplete_features)]
+
+pub trait Iter {
+    type Item<'a> where Self: 'a;
+
+    fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
+
+    fn for_each<F>(mut self, mut f: F)
+        where Self: Sized, F: for<'a> FnMut(Self::Item<'a>)
+    {
+        while let Some(item) = self.next() {
+            f(item);
+        }
+    }
+}
+
+pub struct Windows<T> {
+    items: Vec<T>,
+    start: usize,
+    len: usize,
+}
+
+impl<T> Windows<T> {
+    pub fn new(items: Vec<T>, len: usize) -> Self {
+        Self { items, start: 0, len }
+    }
+}
+
+impl<T> Iter for Windows<T> {
+    type Item<'a> where T: 'a = &'a mut [T];
+
+    fn next<'a>(&'a mut self) -> Option<Self::Item<'a>> {
+        let slice = self.items.get_mut(self.start..self.start + self.len)?;
+        self.start += 1;
+        Some(slice)
+    }
+}
+
+fn main() {
+    Windows::new(vec![1, 2, 3, 4, 5], 3)
+        .for_each(|slice| println!("{:?}", slice));
+}
diff --git a/src/test/ui/issues/issue-18611.stderr b/src/test/ui/issues/issue-18611.stderr
index 22c3470b61e..8872f51753c 100644
--- a/src/test/ui/issues/issue-18611.stderr
+++ b/src/test/ui/issues/issue-18611.stderr
@@ -1,10 +1,8 @@
 error[E0277]: the trait bound `isize: HasState` is not satisfied
-  --> $DIR/issue-18611.rs:1:1
+  --> $DIR/issue-18611.rs:1:4
    |
-LL | / fn add_state(op: <isize as HasState>::State) {
-LL | |
-LL | | }
-   | |_^ the trait `HasState` is not implemented for `isize`
+LL | fn add_state(op: <isize as HasState>::State) {
+   |    ^^^^^^^^^ the trait `HasState` is not implemented for `isize`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-20831-debruijn.stderr b/src/test/ui/issues/issue-20831-debruijn.stderr
index e68482d1caf..03e3311e0f3 100644
--- a/src/test/ui/issues/issue-20831-debruijn.stderr
+++ b/src/test/ui/issues/issue-20831-debruijn.stderr
@@ -1,8 +1,8 @@
 error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
-  --> $DIR/issue-20831-debruijn.rs:28:33
+  --> $DIR/issue-20831-debruijn.rs:28:8
    |
 LL |     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^
    |
 note: first, the lifetime cannot outlive the anonymous lifetime defined on the method body at 28:58...
   --> $DIR/issue-20831-debruijn.rs:28:58
@@ -15,10 +15,10 @@ note: ...but the lifetime must also be valid for the lifetime `'a` as defined on
 LL | impl<'a> Publisher<'a> for MyStruct<'a> {
    |      ^^
 note: ...so that the types are compatible
-  --> $DIR/issue-20831-debruijn.rs:28:33
+  --> $DIR/issue-20831-debruijn.rs:28:8
    |
 LL |     fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^
    = note: expected `Publisher<'_>`
               found `Publisher<'_>`
 
diff --git a/src/test/ui/nll/normalization-bounds-error.stderr b/src/test/ui/nll/normalization-bounds-error.stderr
index d003acd879a..8c7c8918f3f 100644
--- a/src/test/ui/nll/normalization-bounds-error.stderr
+++ b/src/test/ui/nll/normalization-bounds-error.stderr
@@ -1,8 +1,8 @@
 error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'d` due to conflicting requirements
-  --> $DIR/normalization-bounds-error.rs:12:1
+  --> $DIR/normalization-bounds-error.rs:12:4
    |
 LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |    ^^^^^^^^^
    |
 note: first, the lifetime cannot outlive the lifetime `'d` as defined on the function body at 12:14...
   --> $DIR/normalization-bounds-error.rs:12:14
@@ -15,10 +15,10 @@ note: ...but the lifetime must also be valid for the lifetime `'a` as defined on
 LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
    |                  ^^
 note: ...so that the types are compatible
-  --> $DIR/normalization-bounds-error.rs:12:1
+  --> $DIR/normalization-bounds-error.rs:12:4
    |
 LL | fn visit_seq<'d, 'a: 'd>() -> <&'a () as Visitor<'d>>::Value {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |    ^^^^^^^^^
    = note: expected `Visitor<'d>`
               found `Visitor<'_>`
 
diff --git a/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr b/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr
index 9081b7929d9..a0eb7d10bd9 100644
--- a/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr
+++ b/src/test/ui/wf/wf-foreign-fn-decl-ret.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `(): Foo` is not satisfied
-  --> $DIR/wf-foreign-fn-decl-ret.rs:11:5
+  --> $DIR/wf-foreign-fn-decl-ret.rs:11:12
    |
 LL |     pub fn lint_me() -> <() as Foo>::Assoc;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
+   |            ^^^^^^^ the trait `Foo` is not implemented for `()`
 
 error[E0277]: the trait bound `u32: Unsatisfied` is not satisfied
   --> $DIR/wf-foreign-fn-decl-ret.rs:14:32