diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index f611b69905c..e86e01451fe 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -165,10 +165,14 @@ impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> {
         arg: ty::GenericArg<'tcx>,
     ) -> ty::GenericArg<'tcx> {
         let arg = self.typing_env.as_query_input(arg);
-        self.tcx.try_normalize_generic_arg_after_erasing_regions(arg).unwrap_or_else(|_| bug!(
-            "Failed to normalize {:?}, maybe try to call `try_normalize_erasing_regions` instead",
-            arg.value
-        ))
+        self.tcx.try_normalize_generic_arg_after_erasing_regions(arg).unwrap_or_else(|_| {
+            bug!(
+                "Failed to normalize {:?} in typing_env={:?}, \
+                maybe try to call `try_normalize_erasing_regions` instead",
+                arg.value,
+                self.typing_env,
+            )
+        })
     }
 }
 
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index 333ea0214eb..58c0a05df1f 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -8,7 +8,6 @@ use rustc_middle::bug;
 use rustc_middle::ty::print::{PrettyPrinter, Print, PrintError, Printer};
 use rustc_middle::ty::{
     self, GenericArg, GenericArgKind, Instance, ReifyReason, Ty, TyCtxt, TypeVisitableExt,
-    TypingEnv,
 };
 use tracing::debug;
 
@@ -387,23 +386,44 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
     ) -> Result<(), PrintError> {
         let self_ty = self.tcx.type_of(impl_def_id);
         let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id);
-        let (typing_env, mut self_ty, mut impl_trait_ref) =
-            if self.tcx.generics_of(impl_def_id).count() <= args.len() {
-                (
-                    TypingEnv::fully_monomorphized(),
-                    self_ty.instantiate(self.tcx, args),
-                    impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(self.tcx, args)),
-                )
-            } else {
-                // We are probably printing a nested item inside of an impl.
-                // Use the identity substitutions for the impl. We also need
-                // a well-formed param-env, so let's use post-analysis.
-                (
-                    TypingEnv::post_analysis(self.tcx, impl_def_id),
-                    self_ty.instantiate_identity(),
-                    impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()),
-                )
-            };
+        let generics = self.tcx.generics_of(impl_def_id);
+        // We have two cases to worry about here:
+        // 1. We're printing a nested item inside of an impl item, like an inner
+        // function inside of a method. Due to the way that def path printing works,
+        // we'll render this something like `<Ty as Trait>::method::inner_fn`
+        // but we have no substs for this impl since it's not really inheriting
+        // generics from the outer item. We need to use the identity substs, and
+        // to normalize we need to use the correct param-env too.
+        // 2. We're mangling an item with identity substs. This seems to only happen
+        // when generating coverage, since we try to generate coverage for unused
+        // items too, and if something isn't monomorphized then we necessarily don't
+        // have anything to substitute the instance with.
+        // NOTE: We don't support mangling partially substituted but still polymorphic
+        // instances, like `impl<A> Tr<A> for ()` where `A` is substituted w/ `(T,)`.
+        let (typing_env, mut self_ty, mut impl_trait_ref) = if generics.count() > args.len()
+            || &args[..generics.count()]
+                == self
+                    .tcx
+                    .erase_regions(ty::GenericArgs::identity_for_item(self.tcx, impl_def_id))
+                    .as_slice()
+        {
+            (
+                ty::TypingEnv::post_analysis(self.tcx, impl_def_id),
+                self_ty.instantiate_identity(),
+                impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()),
+            )
+        } else {
+            assert!(
+                !args.has_non_region_param(),
+                "should not be mangling partially substituted \
+                polymorphic instance: {impl_def_id:?} {args:?}"
+            );
+            (
+                ty::TypingEnv::fully_monomorphized(),
+                self_ty.instantiate(self.tcx, args),
+                impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(self.tcx, args)),
+            )
+        };
 
         match &mut impl_trait_ref {
             Some(impl_trait_ref) => {
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index b77ad209e2b..4ddf530a00d 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -233,23 +233,44 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
 
         let self_ty = self.tcx.type_of(impl_def_id);
         let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id);
-        let (typing_env, mut self_ty, mut impl_trait_ref) =
-            if self.tcx.generics_of(impl_def_id).count() <= args.len() {
-                (
-                    ty::TypingEnv::fully_monomorphized(),
-                    self_ty.instantiate(self.tcx, args),
-                    impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(self.tcx, args)),
-                )
-            } else {
-                // We are probably printing a nested item inside of an impl.
-                // Use the identity substitutions for the impl. We also need
-                // a well-formed param-env, so let's use post-analysis.
-                (
-                    ty::TypingEnv::post_analysis(self.tcx, impl_def_id),
-                    self_ty.instantiate_identity(),
-                    impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()),
-                )
-            };
+        let generics = self.tcx.generics_of(impl_def_id);
+        // We have two cases to worry about here:
+        // 1. We're printing a nested item inside of an impl item, like an inner
+        // function inside of a method. Due to the way that def path printing works,
+        // we'll render this something like `<Ty as Trait>::method::inner_fn`
+        // but we have no substs for this impl since it's not really inheriting
+        // generics from the outer item. We need to use the identity substs, and
+        // to normalize we need to use the correct param-env too.
+        // 2. We're mangling an item with identity substs. This seems to only happen
+        // when generating coverage, since we try to generate coverage for unused
+        // items too, and if something isn't monomorphized then we necessarily don't
+        // have anything to substitute the instance with.
+        // NOTE: We don't support mangling partially substituted but still polymorphic
+        // instances, like `impl<A> Tr<A> for ()` where `A` is substituted w/ `(T,)`.
+        let (typing_env, mut self_ty, mut impl_trait_ref) = if generics.count() > args.len()
+            || &args[..generics.count()]
+                == self
+                    .tcx
+                    .erase_regions(ty::GenericArgs::identity_for_item(self.tcx, impl_def_id))
+                    .as_slice()
+        {
+            (
+                ty::TypingEnv::post_analysis(self.tcx, impl_def_id),
+                self_ty.instantiate_identity(),
+                impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()),
+            )
+        } else {
+            assert!(
+                !args.has_non_region_param(),
+                "should not be mangling partially substituted \
+                polymorphic instance: {impl_def_id:?} {args:?}"
+            );
+            (
+                ty::TypingEnv::fully_monomorphized(),
+                self_ty.instantiate(self.tcx, args),
+                impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(self.tcx, args)),
+            )
+        };
 
         match &mut impl_trait_ref {
             Some(impl_trait_ref) => {
diff --git a/tests/coverage/generic-unused-impl.cov-map b/tests/coverage/generic-unused-impl.cov-map
new file mode 100644
index 00000000000..7cb6d2f385d
--- /dev/null
+++ b/tests/coverage/generic-unused-impl.cov-map
@@ -0,0 +1,18 @@
+Function name: <generic_unused_impl::W<_> as core::convert::From<[<_ as generic_unused_impl::Foo>::Assoc; 1]>>::from (unused)
+Raw bytes (9): 0x[01, 01, 00, 01, 00, 0a, 05, 03, 06]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Zero) at (prev + 10, 5) to (start + 3, 6)
+Highest counter ID seen: (none)
+
+Function name: generic_unused_impl::main
+Raw bytes (9): 0x[01, 01, 00, 01, 01, 10, 01, 00, 0d]
+Number of files: 1
+- file 0 => global file 1
+Number of expressions: 0
+Number of file 0 mappings: 1
+- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 13)
+Highest counter ID seen: c0
+
diff --git a/tests/coverage/generic-unused-impl.coverage b/tests/coverage/generic-unused-impl.coverage
new file mode 100644
index 00000000000..0c20285f845
--- /dev/null
+++ b/tests/coverage/generic-unused-impl.coverage
@@ -0,0 +1,17 @@
+   LL|       |trait Foo {
+   LL|       |    type Assoc;
+   LL|       |
+   LL|       |    fn from(s: Self::Assoc) -> Self;
+   LL|       |}
+   LL|       |
+   LL|       |struct W<T>(T);
+   LL|       |
+   LL|       |impl<T: Foo> From<[T::Assoc; 1]> for W<T> {
+   LL|      0|    fn from(from: [T::Assoc; 1]) -> Self {
+   LL|      0|        let [item] = from;
+   LL|      0|        W(Foo::from(item))
+   LL|      0|    }
+   LL|       |}
+   LL|       |
+   LL|      1|fn main() {}
+
diff --git a/tests/coverage/generic-unused-impl.rs b/tests/coverage/generic-unused-impl.rs
new file mode 100644
index 00000000000..e44b1ca8a1d
--- /dev/null
+++ b/tests/coverage/generic-unused-impl.rs
@@ -0,0 +1,16 @@
+trait Foo {
+    type Assoc;
+
+    fn from(s: Self::Assoc) -> Self;
+}
+
+struct W<T>(T);
+
+impl<T: Foo> From<[T::Assoc; 1]> for W<T> {
+    fn from(from: [T::Assoc; 1]) -> Self {
+        let [item] = from;
+        W(Foo::from(item))
+    }
+}
+
+fn main() {}