diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index 9271a2f4dc718..a581726a15c9c 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -52,11 +52,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 Some(error_info) => error_info.to_universe_info(old_universe),
                 None => UniverseInfo::other(),
             };
-            for u in old_universe..universe {
-                self.borrowck_context
-                    .constraints
-                    .universe_causes
-                    .insert(u + 1, universe_info.clone());
+            for u in (old_universe + 1)..=universe {
+                self.borrowck_context.constraints.universe_causes.insert(u, universe_info.clone());
             }
         }
 
@@ -71,15 +68,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     where
         T: TypeFoldable<'tcx>,
     {
+        let old_universe = self.infcx.universe();
+
         let (instantiated, _) =
             self.infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
 
-        for u in 0..canonical.max_universe.as_u32() {
-            let info = UniverseInfo::other();
-            self.borrowck_context
-                .constraints
-                .universe_causes
-                .insert(ty::UniverseIndex::from_u32(u), info);
+        for u in (old_universe + 1)..=self.infcx.universe() {
+            self.borrowck_context.constraints.universe_causes.insert(u, UniverseInfo::other());
         }
 
         instantiated
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index e0140e281ee73..7d71f0b23d180 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -8,7 +8,6 @@ use rustc_infer::infer::InferCtxt;
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::traits::query::OutlivesBound;
 use rustc_middle::ty::{self, RegionVid, Ty};
-use rustc_span::DUMMY_SP;
 use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
 use std::rc::Rc;
 use type_op::TypeOpOutput;
@@ -219,6 +218,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
     }
 
     pub(crate) fn create(mut self) -> CreateResult<'tcx> {
+        let span = self.infcx.tcx.def_span(self.universal_regions.defining_ty.def_id());
         let unnormalized_input_output_tys = self
             .universal_regions
             .unnormalized_input_tys
@@ -250,7 +250,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
                         self.infcx
                             .tcx
                             .sess
-                            .delay_span_bug(DUMMY_SP, &format!("failed to normalize {:?}", ty));
+                            .delay_span_bug(span, &format!("failed to normalize {:?}", ty));
                         TypeOpOutput {
                             output: self.infcx.tcx.ty_error(),
                             constraints: None,
@@ -301,8 +301,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
                 &self.region_bound_pairs,
                 self.implicit_region_bound,
                 self.param_env,
-                Locations::All(DUMMY_SP),
-                DUMMY_SP,
+                Locations::All(span),
+                span,
                 ConstraintCategory::Internal,
                 &mut self.constraints,
             )
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index 4431a2e8ec60d..a66ddd27dbb2e 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -7,16 +7,11 @@
 //! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
 //! contain revealed `impl Trait` values).
 
-use crate::type_check::constraint_conversion::ConstraintConversion;
 use rustc_index::vec::Idx;
 use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_middle::mir::*;
 use rustc_middle::ty::Ty;
 use rustc_span::Span;
-use rustc_span::DUMMY_SP;
-use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
-use rustc_trait_selection::traits::query::Fallible;
-use type_op::TypeOpOutput;
 
 use crate::universal_regions::UniversalRegions;
 
@@ -185,7 +180,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         }
     }
 
-    #[instrument(skip(self, span), level = "debug")]
+    #[instrument(skip(self), level = "debug")]
     fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {
         if let Err(_) =
             self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
@@ -194,13 +189,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             // `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd
             // like to normalize *before* inserting into `local_decls`, but
             // doing so ends up causing some other trouble.
-            let b = match self.normalize_and_add_constraints(b) {
-                Ok(n) => n,
-                Err(_) => {
-                    debug!("equate_inputs_and_outputs: NoSolution");
-                    b
-                }
-            };
+            let b = self.normalize(b, Locations::All(span));
 
             // Note: if we have to introduce new placeholders during normalization above, then we won't have
             // added those universes to the universe info, which we would want in `relate_tys`.
@@ -218,28 +207,4 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             }
         }
     }
-
-    pub(crate) fn normalize_and_add_constraints(&mut self, t: Ty<'tcx>) -> Fallible<Ty<'tcx>> {
-        let TypeOpOutput { output: norm_ty, constraints, .. } =
-            self.param_env.and(type_op::normalize::Normalize::new(t)).fully_perform(self.infcx)?;
-
-        debug!("{:?} normalized to {:?}", t, norm_ty);
-
-        for data in constraints {
-            ConstraintConversion::new(
-                self.infcx,
-                &self.borrowck_context.universal_regions,
-                &self.region_bound_pairs,
-                self.implicit_region_bound,
-                self.param_env,
-                Locations::All(DUMMY_SP),
-                DUMMY_SP,
-                ConstraintCategory::Internal,
-                &mut self.borrowck_context.constraints,
-            )
-            .convert_all(&*data);
-        }
-
-        Ok(norm_ty)
-    }
 }
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index d03f036964857..101b33c4580f9 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -138,8 +138,6 @@ pub(crate) fn type_check<'mir, 'tcx>(
     use_polonius: bool,
 ) -> MirTypeckResults<'tcx> {
     let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
-    let mut universe_causes = FxHashMap::default();
-    universe_causes.insert(ty::UniverseIndex::from_u32(0), UniverseInfo::other());
     let mut constraints = MirTypeckRegionConstraints {
         placeholder_indices: PlaceholderIndices::default(),
         placeholder_index_to_region: IndexVec::default(),
@@ -148,7 +146,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
         member_constraints: MemberConstraintSet::default(),
         closure_bounds_mapping: Default::default(),
         type_tests: Vec::default(),
-        universe_causes,
+        universe_causes: FxHashMap::default(),
     };
 
     let CreateResult {
@@ -165,9 +163,8 @@ pub(crate) fn type_check<'mir, 'tcx>(
 
     debug!(?normalized_inputs_and_output);
 
-    for u in ty::UniverseIndex::ROOT..infcx.universe() {
-        let info = UniverseInfo::other();
-        constraints.universe_causes.insert(u, info);
+    for u in ty::UniverseIndex::ROOT..=infcx.universe() {
+        constraints.universe_causes.insert(u, UniverseInfo::other());
     }
 
     let mut borrowck_context = BorrowCheckContext {
diff --git a/src/test/ui/nll/closure-malformed-projection-input-issue-102800.rs b/src/test/ui/nll/closure-malformed-projection-input-issue-102800.rs
new file mode 100644
index 0000000000000..25f47f5b6f6c9
--- /dev/null
+++ b/src/test/ui/nll/closure-malformed-projection-input-issue-102800.rs
@@ -0,0 +1,31 @@
+// Regression test for #102800
+//
+// Here we are generating higher-ranked region constraints when normalizing and relating closure
+// input types. Previously this was an ICE in the error path because we didn't register enough
+// diagnostic information to render the higher-ranked subtyping error.
+
+// check-fail
+
+trait Trait {
+    type Ty;
+}
+
+impl Trait for &'static () {
+    type Ty = ();
+}
+
+fn main() {
+    let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
+    //~^ ERROR lifetime may not live long enough
+    //~| ERROR higher-ranked subtype error
+    //~| ERROR higher-ranked subtype error
+    //~| ERROR implementation of `Trait` is not general enough
+    //~| ERROR implementation of `Trait` is not general enough
+    //~| ERROR implementation of `Trait` is not general enough
+    //~| ERROR implementation of `Trait` is not general enough
+    //~| ERROR implementation of `Trait` is not general enough
+    //~| ERROR implementation of `Trait` is not general enough
+    //~| ERROR implementation of `Trait` is not general enough
+    //~| ERROR implementation of `Trait` is not general enough
+    //~| ERROR implementation of `Trait` is not general enough
+}
diff --git a/src/test/ui/nll/closure-malformed-projection-input-issue-102800.stderr b/src/test/ui/nll/closure-malformed-projection-input-issue-102800.stderr
new file mode 100644
index 0000000000000..dbd5dabd1dacc
--- /dev/null
+++ b/src/test/ui/nll/closure-malformed-projection-input-issue-102800.stderr
@@ -0,0 +1,104 @@
+error: lifetime may not live long enough
+  --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
+   |
+LL |     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
+   |                                                ^-^
+   |                                                ||
+   |                                                |has type `<&'1 () as Trait>::Ty`
+   |                                                requires that `'1` must outlive `'static`
+
+error: higher-ranked subtype error
+  --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
+   |
+LL |     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
+   |                                                ^^^
+
+error: higher-ranked subtype error
+  --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
+   |
+LL |     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
+   |                                                ^^^
+
+error: implementation of `Trait` is not general enough
+  --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
+   |
+LL |     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
+   |                                                ^^^^^^ implementation of `Trait` is not general enough
+   |
+   = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
+   = note: ...but `Trait` is actually implemented for the type `&'static ()`
+
+error: implementation of `Trait` is not general enough
+  --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:12
+   |
+LL |     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough
+   |
+   = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
+   = note: ...but `Trait` is actually implemented for the type `&'static ()`
+
+error: implementation of `Trait` is not general enough
+  --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:12
+   |
+LL |     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough
+   |
+   = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
+   = note: ...but `Trait` is actually implemented for the type `&'static ()`
+
+error: implementation of `Trait` is not general enough
+  --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:12
+   |
+LL |     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough
+   |
+   = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
+   = note: ...but `Trait` is actually implemented for the type `&'static ()`
+
+error: implementation of `Trait` is not general enough
+  --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:12
+   |
+LL |     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Trait` is not general enough
+   |
+   = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
+   = note: ...but `Trait` is actually implemented for the type `&'static ()`
+
+error: implementation of `Trait` is not general enough
+  --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
+   |
+LL |     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
+   |                                                ^^^^^^ implementation of `Trait` is not general enough
+   |
+   = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
+   = note: ...but `Trait` is actually implemented for the type `&'static ()`
+
+error: implementation of `Trait` is not general enough
+  --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
+   |
+LL |     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
+   |                                                ^^^^^^ implementation of `Trait` is not general enough
+   |
+   = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
+   = note: ...but `Trait` is actually implemented for the type `&'static ()`
+
+error: implementation of `Trait` is not general enough
+  --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
+   |
+LL |     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
+   |                                                ^^^^^^ implementation of `Trait` is not general enough
+   |
+   = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
+   = note: ...but `Trait` is actually implemented for the type `&'static ()`
+
+error: implementation of `Trait` is not general enough
+  --> $DIR/closure-malformed-projection-input-issue-102800.rs:18:48
+   |
+LL |     let _: for<'a> fn(<&'a () as Trait>::Ty) = |_| {};
+   |                                                ^^^^^^ implementation of `Trait` is not general enough
+   |
+   = note: `&'0 ()` must implement `Trait`, for any lifetime `'0`...
+   = note: ...but `Trait` is actually implemented for the type `&'static ()`
+
+error: aborting due to 12 previous errors
+