diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index b0150bc11920b..72f353f06ff52 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -45,10 +45,25 @@ pub trait Printer<'tcx>: Sized {
         &mut self,
         impl_def_id: DefId,
         args: &'tcx [GenericArg<'tcx>],
-        self_ty: Ty<'tcx>,
-        trait_ref: Option<ty::TraitRef<'tcx>>,
     ) -> Result<(), PrintError> {
-        self.default_print_impl_path(impl_def_id, args, self_ty, trait_ref)
+        let tcx = self.tcx();
+        let self_ty = tcx.type_of(impl_def_id);
+        let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
+        let (self_ty, impl_trait_ref) = if tcx.generics_of(impl_def_id).count() <= args.len() {
+            (
+                self_ty.instantiate(tcx, args),
+                impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate(tcx, args)),
+            )
+        } else {
+            // We are probably printing a nested item inside of an impl.
+            // Use the identity substitutions for the impl.
+            (
+                self_ty.instantiate_identity(),
+                impl_trait_ref.map(|impl_trait_ref| impl_trait_ref.instantiate_identity()),
+            )
+        };
+
+        self.default_print_impl_path(impl_def_id, self_ty, impl_trait_ref)
     }
 
     fn print_region(&mut self, region: ty::Region<'tcx>) -> Result<(), PrintError>;
@@ -107,23 +122,7 @@ pub trait Printer<'tcx>: Sized {
                 self.path_crate(def_id.krate)
             }
 
-            DefPathData::Impl => {
-                let generics = self.tcx().generics_of(def_id);
-                let self_ty = self.tcx().type_of(def_id);
-                let impl_trait_ref = self.tcx().impl_trait_ref(def_id);
-                let (self_ty, impl_trait_ref) = if args.len() >= generics.count() {
-                    (
-                        self_ty.instantiate(self.tcx(), args),
-                        impl_trait_ref.map(|i| i.instantiate(self.tcx(), args)),
-                    )
-                } else {
-                    (
-                        self_ty.instantiate_identity(),
-                        impl_trait_ref.map(|i| i.instantiate_identity()),
-                    )
-                };
-                self.print_impl_path(def_id, args, self_ty, impl_trait_ref)
-            }
+            DefPathData::Impl => self.print_impl_path(def_id, args),
 
             _ => {
                 let parent_def_id = DefId { index: key.parent.unwrap(), ..def_id };
@@ -201,7 +200,6 @@ pub trait Printer<'tcx>: Sized {
     fn default_print_impl_path(
         &mut self,
         impl_def_id: DefId,
-        _args: &'tcx [GenericArg<'tcx>],
         self_ty: Ty<'tcx>,
         impl_trait_ref: Option<ty::TraitRef<'tcx>>,
     ) -> Result<(), PrintError> {
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index 0d6d8488a23ca..333ea0214eb3f 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -8,6 +8,7 @@ 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;
 
@@ -383,14 +384,26 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
         &mut self,
         impl_def_id: DefId,
         args: &'tcx [GenericArg<'tcx>],
-        mut self_ty: Ty<'tcx>,
-        mut impl_trait_ref: Option<ty::TraitRef<'tcx>>,
     ) -> Result<(), PrintError> {
-        let mut typing_env = ty::TypingEnv::post_analysis(self.tcx, impl_def_id);
-        if !args.is_empty() {
-            typing_env.param_env =
-                ty::EarlyBinder::bind(typing_env.param_env).instantiate(self.tcx, args);
-        }
+        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()),
+                )
+            };
 
         match &mut impl_trait_ref {
             Some(impl_trait_ref) => {
@@ -403,7 +416,7 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
             }
         }
 
-        self.default_print_impl_path(impl_def_id, args, self_ty, impl_trait_ref)
+        self.default_print_impl_path(impl_def_id, self_ty, impl_trait_ref)
     }
 }
 
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 0ca47eba5e81e..b77ad209e2bd8 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -14,8 +14,8 @@ use rustc_middle::bug;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::print::{Print, PrintError, Printer};
 use rustc_middle::ty::{
-    self, EarlyBinder, FloatTy, GenericArg, GenericArgKind, Instance, IntTy, ReifyReason, Ty,
-    TyCtxt, TypeVisitable, TypeVisitableExt, UintTy,
+    self, FloatTy, GenericArg, GenericArgKind, Instance, IntTy, ReifyReason, Ty, TyCtxt,
+    TypeVisitable, TypeVisitableExt, UintTy,
 };
 use rustc_span::kw;
 
@@ -227,17 +227,29 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
         &mut self,
         impl_def_id: DefId,
         args: &'tcx [GenericArg<'tcx>],
-        mut self_ty: Ty<'tcx>,
-        mut impl_trait_ref: Option<ty::TraitRef<'tcx>>,
     ) -> Result<(), PrintError> {
         let key = self.tcx.def_key(impl_def_id);
         let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id };
 
-        let mut typing_env = ty::TypingEnv::post_analysis(self.tcx, impl_def_id);
-        if !args.is_empty() {
-            typing_env.param_env =
-                EarlyBinder::bind(typing_env.param_env).instantiate(self.tcx, args);
-        }
+        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()),
+                )
+            };
 
         match &mut impl_trait_ref {
             Some(impl_trait_ref) => {
diff --git a/tests/ui/symbol-names/normalize-in-param-env.rs b/tests/ui/symbol-names/normalize-in-param-env.rs
new file mode 100644
index 0000000000000..a1453eb13eff5
--- /dev/null
+++ b/tests/ui/symbol-names/normalize-in-param-env.rs
@@ -0,0 +1,38 @@
+//@ revisions: legacy v0
+//@[v0] compile-flags: -C symbol-mangling-version=v0
+//@[legacy] compile-flags: -C symbol-mangling-version=legacy -Zunstable-options
+//@ build-pass
+
+pub struct Vec2;
+
+pub trait Point {
+    type S;
+}
+impl Point for Vec2 {
+    type S = f32;
+}
+
+pub trait Point2: Point<S = Self::S2> {
+    type S2;
+}
+impl Point2 for Vec2 {
+    type S2 = Self::S;
+}
+
+trait MyFrom<T> {
+    fn my_from();
+}
+impl<P: Point2> MyFrom<P::S> for P {
+    fn my_from() {
+        // This is just a really dumb way to force the legacy symbol mangling to
+        // mangle the closure's parent impl def path *with* args. Otherwise,
+        // legacy symbol mangling will strip the args from the instance, meaning
+        // that we don't trigger the bug.
+        let c = || {};
+        let x = Box::new(c) as Box<dyn Fn()>;
+    }
+}
+
+fn main() {
+    <Vec2 as MyFrom<_>>::my_from();
+}