about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs388
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs357
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs45
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs2
-rw-r--r--tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs2
-rw-r--r--tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr4
7 files changed, 456 insertions, 349 deletions
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index ca2e14ee359..7a0890e50da 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -1,6 +1,6 @@
 use crate::errors::{
     self, AssocTypeBindingNotAllowed, ManualImplementation, MissingTypeParams,
-    ParenthesizedFnTraitExpansion,
+    ParenthesizedFnTraitExpansion, TraitObjectDeclaredWithNoTraits,
 };
 use crate::fluent_generated as fluent;
 use crate::hir_ty_lowering::HirTyLowerer;
@@ -8,19 +8,26 @@ use crate::traits::error_reporting::report_object_safety_error;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::unord::UnordMap;
+use rustc_errors::MultiSpan;
 use rustc_errors::{
     codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed,
 };
 use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::traits::FulfillmentError;
 use rustc_middle::query::Key;
-use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, suggest_constraining_type_param};
+use rustc_middle::ty::{AdtDef, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{Binder, TraitRef};
 use rustc_session::parse::feature_err;
 use rustc_span::edit_distance::find_best_match_for_name;
-use rustc_span::symbol::{sym, Ident};
+use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::BytePos;
 use rustc_span::{Span, Symbol, DUMMY_SP};
-use rustc_trait_selection::traits::object_safety_violations_for_assoc_item;
+use rustc_trait_selection::traits::{
+    object_safety_violations_for_assoc_item, TraitAliasExpansionInfo,
+};
 
 impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// On missing type parameters, emit an E0393 error and provide a structured suggestion using
@@ -1024,6 +1031,170 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             Ok(())
         }
     }
+
+    pub fn report_prohibit_generics_error<'a>(
+        &self,
+        segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
+        args_visitors: impl Iterator<Item = &'a hir::GenericArg<'a>> + Clone,
+        err_extend: GenericsArgsErrExtend<'_>,
+    ) -> ErrorGuaranteed {
+        #[derive(PartialEq, Eq, Hash)]
+        enum ProhibitGenericsArg {
+            Lifetime,
+            Type,
+            Const,
+            Infer,
+        }
+
+        let mut prohibit_args = FxIndexSet::default();
+        args_visitors.for_each(|arg| {
+            match arg {
+                hir::GenericArg::Lifetime(_) => prohibit_args.insert(ProhibitGenericsArg::Lifetime),
+                hir::GenericArg::Type(_) => prohibit_args.insert(ProhibitGenericsArg::Type),
+                hir::GenericArg::Const(_) => prohibit_args.insert(ProhibitGenericsArg::Const),
+                hir::GenericArg::Infer(_) => prohibit_args.insert(ProhibitGenericsArg::Infer),
+            };
+        });
+
+        let types_and_spans: Vec<_> = segments
+            .clone()
+            .flat_map(|segment| {
+                if segment.args().args.is_empty() {
+                    None
+                } else {
+                    Some((
+                        match segment.res {
+                            hir::def::Res::PrimTy(ty) => {
+                                format!("{} `{}`", segment.res.descr(), ty.name())
+                            }
+                            hir::def::Res::Def(_, def_id)
+                                if let Some(name) = self.tcx().opt_item_name(def_id) =>
+                            {
+                                format!("{} `{name}`", segment.res.descr())
+                            }
+                            hir::def::Res::Err => "this type".to_string(),
+                            _ => segment.res.descr().to_string(),
+                        },
+                        segment.ident.span,
+                    ))
+                }
+            })
+            .collect();
+        let this_type = match &types_and_spans[..] {
+            [.., _, (last, _)] => format!(
+                "{} and {last}",
+                types_and_spans[..types_and_spans.len() - 1]
+                    .iter()
+                    .map(|(x, _)| x.as_str())
+                    .intersperse(", ")
+                    .collect::<String>()
+            ),
+            [(only, _)] => only.to_string(),
+            [] => "this type".to_string(),
+        };
+
+        let arg_spans: Vec<Span> = segments
+            .clone()
+            .flat_map(|segment| segment.args().args)
+            .map(|arg| arg.span())
+            .collect();
+
+        let mut kinds = Vec::with_capacity(4);
+        prohibit_args.iter().for_each(|arg| match arg {
+            ProhibitGenericsArg::Lifetime => kinds.push("lifetime"),
+            ProhibitGenericsArg::Type => kinds.push("type"),
+            ProhibitGenericsArg::Const => kinds.push("const"),
+            ProhibitGenericsArg::Infer => kinds.push("generic"),
+        });
+
+        let (kind, s) = match kinds[..] {
+            [.., _, last] => (
+                format!(
+                    "{} and {last}",
+                    kinds[..kinds.len() - 1]
+                        .iter()
+                        .map(|&x| x)
+                        .intersperse(", ")
+                        .collect::<String>()
+                ),
+                "s",
+            ),
+            [only] => (only.to_string(), ""),
+            [] => unreachable!("expected at least one generic to prohibit"),
+        };
+        let last_span = *arg_spans.last().unwrap();
+        let span: MultiSpan = arg_spans.into();
+        let mut err = struct_span_code_err!(
+            self.tcx().dcx(),
+            span,
+            E0109,
+            "{kind} arguments are not allowed on {this_type}",
+        );
+        err.span_label(last_span, format!("{kind} argument{s} not allowed"));
+        for (what, span) in types_and_spans {
+            err.span_label(span, format!("not allowed on {what}"));
+        }
+        generics_args_err_extend(self.tcx(), segments.clone(), &mut err, err_extend);
+        let reported = err.emit();
+        self.set_tainted_by_errors(reported);
+        reported
+    }
+
+    pub fn report_trait_object_addition_traits_error(
+        &self,
+        regular_traits: &Vec<TraitAliasExpansionInfo<'_>>,
+    ) -> ErrorGuaranteed {
+        let tcx = self.tcx();
+        let first_trait = &regular_traits[0];
+        let additional_trait = &regular_traits[1];
+        let mut err = struct_span_code_err!(
+            tcx.dcx(),
+            additional_trait.bottom().1,
+            E0225,
+            "only auto traits can be used as additional traits in a trait object"
+        );
+        additional_trait.label_with_exp_info(
+            &mut err,
+            "additional non-auto trait",
+            "additional use",
+        );
+        first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use");
+        err.help(format!(
+            "consider creating a new trait with all of these as supertraits and using that \
+             trait here instead: `trait NewTrait: {} {{}}`",
+            regular_traits
+                .iter()
+                // FIXME: This should `print_sugared`, but also needs to integrate projection bounds...
+                .map(|t| t.trait_ref().print_only_trait_path().to_string())
+                .collect::<Vec<_>>()
+                .join(" + "),
+        ));
+        err.note(
+            "auto-traits like `Send` and `Sync` are traits that have special properties; \
+             for more information on them, visit \
+             <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
+        );
+        let reported = err.emit();
+        self.set_tainted_by_errors(reported);
+        reported
+    }
+
+    pub fn report_trait_object_with_no_traits_error(
+        &self,
+        span: Span,
+        trait_bounds: &Vec<(Binder<'tcx, TraitRef<'tcx>>, Span)>,
+    ) -> ErrorGuaranteed {
+        let tcx = self.tcx();
+        let trait_alias_span = trait_bounds
+            .iter()
+            .map(|&(trait_ref, _)| trait_ref.def_id())
+            .find(|&trait_ref| tcx.is_trait_alias(trait_ref))
+            .map(|trait_ref| tcx.def_span(trait_ref));
+        let reported =
+            tcx.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
+        self.set_tainted_by_errors(reported);
+        reported
+    }
 }
 
 /// Emits an error regarding forbidden type binding associations
@@ -1031,7 +1202,7 @@ pub fn prohibit_assoc_item_binding(
     tcx: TyCtxt<'_>,
     span: Span,
     segment: Option<(&hir::PathSegment<'_>, Span)>,
-) {
+) -> ErrorGuaranteed {
     tcx.dcx().emit_err(AssocTypeBindingNotAllowed {
         span,
         fn_trait_expansion: if let Some((segment, span)) = segment
@@ -1044,7 +1215,7 @@ pub fn prohibit_assoc_item_binding(
         } else {
             None
         },
-    });
+    })
 }
 
 pub(crate) fn fn_trait_to_string(
@@ -1099,3 +1270,208 @@ pub(crate) fn fn_trait_to_string(
         format!("{}<{}, Output={}>", trait_segment.ident, args, ret)
     }
 }
+
+/// Used for generics args error extend.
+pub enum GenericsArgsErrExtend<'tcx> {
+    EnumVariant {
+        qself: &'tcx hir::Ty<'tcx>,
+        assoc_segment: &'tcx hir::PathSegment<'tcx>,
+        adt_def: AdtDef<'tcx>,
+    },
+    OpaqueTy,
+    PrimTy(hir::PrimTy),
+    SelfTyAlias {
+        def_id: DefId,
+        span: Span,
+    },
+    SelfTyParam(Span),
+    TyParam(DefId),
+    DefVariant,
+    None,
+}
+
+fn generics_args_err_extend<'a>(
+    tcx: TyCtxt<'_>,
+    segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
+    err: &mut Diag<'_>,
+    err_extend: GenericsArgsErrExtend<'_>,
+) {
+    match err_extend {
+        GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def } => {
+            err.note("enum variants can't have type parameters");
+            let type_name = tcx.item_name(adt_def.did());
+            let msg = format!(
+                "you might have meant to specify type parameters on enum \
+                `{type_name}`"
+            );
+            let Some(args) = assoc_segment.args else {
+                return;
+            };
+            // Get the span of the generics args *including* the leading `::`.
+            // We do so by stretching args.span_ext to the left by 2. Earlier
+            // it was done based on the end of assoc segment but that sometimes
+            // led to impossible spans and caused issues like #116473
+            let args_span = args.span_ext.with_lo(args.span_ext.lo() - BytePos(2));
+            if tcx.generics_of(adt_def.did()).count() == 0 {
+                // FIXME(estebank): we could also verify that the arguments being
+                // work for the `enum`, instead of just looking if it takes *any*.
+                err.span_suggestion_verbose(
+                    args_span,
+                    format!("{type_name} doesn't have generic parameters"),
+                    "",
+                    Applicability::MachineApplicable,
+                );
+                return;
+            }
+            let Ok(snippet) = tcx.sess.source_map().span_to_snippet(args_span) else {
+                err.note(msg);
+                return;
+            };
+            let (qself_sugg_span, is_self) =
+                if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
+                    // If the path segment already has type params, we want to overwrite
+                    // them.
+                    match &path.segments {
+                        // `segment` is the previous to last element on the path,
+                        // which would normally be the `enum` itself, while the last
+                        // `_` `PathSegment` corresponds to the variant.
+                        [
+                            ..,
+                            hir::PathSegment {
+                                ident, args, res: Res::Def(DefKind::Enum, _), ..
+                            },
+                            _,
+                        ] => (
+                            // We need to include the `::` in `Type::Variant::<Args>`
+                            // to point the span to `::<Args>`, not just `<Args>`.
+                            ident
+                                .span
+                                .shrink_to_hi()
+                                .to(args.map_or(ident.span.shrink_to_hi(), |a| a.span_ext)),
+                            false,
+                        ),
+                        [segment] => {
+                            (
+                                // We need to include the `::` in `Type::Variant::<Args>`
+                                // to point the span to `::<Args>`, not just `<Args>`.
+                                segment.ident.span.shrink_to_hi().to(segment
+                                    .args
+                                    .map_or(segment.ident.span.shrink_to_hi(), |a| a.span_ext)),
+                                kw::SelfUpper == segment.ident.name,
+                            )
+                        }
+                        _ => {
+                            err.note(msg);
+                            return;
+                        }
+                    }
+                } else {
+                    err.note(msg);
+                    return;
+                };
+            let suggestion = vec![
+                if is_self {
+                    // Account for people writing `Self::Variant::<Args>`, where
+                    // `Self` is the enum, and suggest replacing `Self` with the
+                    // appropriate type: `Type::<Args>::Variant`.
+                    (qself.span, format!("{type_name}{snippet}"))
+                } else {
+                    (qself_sugg_span, snippet)
+                },
+                (args_span, String::new()),
+            ];
+            err.multipart_suggestion_verbose(msg, suggestion, Applicability::MaybeIncorrect);
+        }
+        GenericsArgsErrExtend::PrimTy(prim_ty) => {
+            let name = prim_ty.name_str();
+            for segment in segments {
+                if let Some(args) = segment.args {
+                    err.span_suggestion_verbose(
+                        segment.ident.span.shrink_to_hi().to(args.span_ext),
+                        format!("primitive type `{name}` doesn't have generic parameters"),
+                        "",
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
+        }
+        GenericsArgsErrExtend::OpaqueTy => {
+            err.note("`impl Trait` types can't have type parameters");
+        }
+        GenericsArgsErrExtend::DefVariant => {
+            err.note("enum variants can't have type parameters");
+        }
+        GenericsArgsErrExtend::TyParam(def_id) => {
+            if let Some(span) = tcx.def_ident_span(def_id) {
+                let name = tcx.item_name(def_id);
+                err.span_note(span, format!("type parameter `{name}` defined here"));
+            }
+        }
+        GenericsArgsErrExtend::SelfTyParam(span) => {
+            err.span_suggestion_verbose(
+                span,
+                "the `Self` type doesn't accept type parameters",
+                "",
+                Applicability::MaybeIncorrect,
+            );
+        }
+        GenericsArgsErrExtend::SelfTyAlias { def_id, span } => {
+            let ty = tcx.at(span).type_of(def_id).instantiate_identity();
+            let span_of_impl = tcx.span_of_impl(def_id);
+            let def_id = match *ty.kind() {
+                ty::Adt(self_def, _) => self_def.did(),
+                _ => return,
+            };
+
+            let type_name = tcx.item_name(def_id);
+            let span_of_ty = tcx.def_ident_span(def_id);
+            let generics = tcx.generics_of(def_id).count();
+
+            let msg = format!("`Self` is of type `{ty}`");
+            if let (Ok(i_sp), Some(t_sp)) = (span_of_impl, span_of_ty) {
+                let mut span: MultiSpan = vec![t_sp].into();
+                span.push_span_label(
+                    i_sp,
+                    format!("`Self` is on type `{type_name}` in this `impl`"),
+                );
+                let mut postfix = "";
+                if generics == 0 {
+                    postfix = ", which doesn't have generic parameters";
+                }
+                span.push_span_label(t_sp, format!("`Self` corresponds to this type{postfix}"));
+                err.span_note(span, msg);
+            } else {
+                err.note(msg);
+            }
+            for segment in segments {
+                if let Some(args) = segment.args
+                    && segment.ident.name == kw::SelfUpper
+                {
+                    if generics == 0 {
+                        // FIXME(estebank): we could also verify that the arguments being
+                        // work for the `enum`, instead of just looking if it takes *any*.
+                        err.span_suggestion_verbose(
+                            segment.ident.span.shrink_to_hi().to(args.span_ext),
+                            "the `Self` type doesn't accept type parameters",
+                            "",
+                            Applicability::MachineApplicable,
+                        );
+                        return;
+                    } else {
+                        err.span_suggestion_verbose(
+                            segment.ident.span,
+                            format!(
+                                "the `Self` type doesn't accept type parameters, use the \
+                                concrete type's name `{type_name}` instead if you want to \
+                                specify its type parameters"
+                            ),
+                            type_name,
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
+            }
+        }
+        _ => {}
+    }
+}
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 8886a78c6ec..f726f2a7b89 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -14,7 +14,7 @@
 //! trait references and bounds.
 
 mod bounds;
-mod errors;
+pub mod errors;
 pub mod generics;
 mod lint;
 mod object_safety;
@@ -22,14 +22,14 @@ mod object_safety;
 use crate::bounds::Bounds;
 use crate::collect::HirPlaceholderCollector;
 use crate::errors::AmbiguousLifetimeBound;
-use crate::hir_ty_lowering::errors::prohibit_assoc_item_binding;
+use crate::hir_ty_lowering::errors::{prohibit_assoc_item_binding, GenericsArgsErrExtend};
 use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
 use crate::middle::resolve_bound_vars as rbv;
 use crate::require_c_abi_if_c_variadic;
 use rustc_ast::TraitObjectSyntax;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_errors::{
-    codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, FatalError, MultiSpan,
+    codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, FatalError,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
@@ -46,7 +46,7 @@ use rustc_middle::ty::{
 use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::symbol::{kw, Ident, Symbol};
-use rustc_span::{sym, BytePos, Span, DUMMY_SP};
+use rustc_span::{sym, Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use rustc_trait_selection::traits::wf::object_region_bounds;
 use rustc_trait_selection::traits::{self, ObligationCtxt};
@@ -632,7 +632,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         trait_ref: &hir::TraitRef<'tcx>,
         self_ty: Ty<'tcx>,
     ) -> ty::TraitRef<'tcx> {
-        self.prohibit_generic_args(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
+        let _ = self.prohibit_generic_args(
+            trait_ref.path.segments.split_last().unwrap().1.iter(),
+            GenericsArgsErrExtend::None,
+        );
 
         self.lower_mono_trait_ref(
             trait_ref.path.span,
@@ -681,7 +684,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
         let trait_segment = trait_ref.path.segments.last().unwrap();
 
-        self.prohibit_generic_args(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
+        let _ = self.prohibit_generic_args(
+            trait_ref.path.segments.split_last().unwrap().1.iter(),
+            GenericsArgsErrExtend::None,
+        );
         self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
 
         let (generic_args, arg_count) = self.lower_generic_args_of_path(
@@ -995,8 +1001,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         hir_ref_id: hir::HirId,
         span: Span,
         qself_ty: Ty<'tcx>,
-        qself: &hir::Ty<'_>,
-        assoc_segment: &hir::PathSegment<'tcx>,
+        qself: &'tcx hir::Ty<'tcx>,
+        assoc_segment: &'tcx hir::PathSegment<'tcx>,
         permit_variants: bool,
     ) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
         debug!(%qself_ty, ?assoc_segment.ident);
@@ -1020,99 +1026,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 if let Some(variant_def) = variant_def {
                     if permit_variants {
                         tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
-                        self.prohibit_generic_args(slice::from_ref(assoc_segment).iter(), |err| {
-                            err.note("enum variants can't have type parameters");
-                            let type_name = tcx.item_name(adt_def.did());
-                            let msg = format!(
-                                "you might have meant to specify type parameters on enum \
-                                 `{type_name}`"
-                            );
-                            let Some(args) = assoc_segment.args else {
-                                return;
-                            };
-                            // Get the span of the generics args *including* the leading `::`.
-                            // We do so by stretching args.span_ext to the left by 2. Earlier
-                            // it was done based on the end of assoc segment but that sometimes
-                            // led to impossible spans and caused issues like #116473
-                            let args_span = args.span_ext.with_lo(args.span_ext.lo() - BytePos(2));
-                            if tcx.generics_of(adt_def.did()).count() == 0 {
-                                // FIXME(estebank): we could also verify that the arguments being
-                                // work for the `enum`, instead of just looking if it takes *any*.
-                                err.span_suggestion_verbose(
-                                    args_span,
-                                    format!("{type_name} doesn't have generic parameters"),
-                                    "",
-                                    Applicability::MachineApplicable,
-                                );
-                                return;
-                            }
-                            let Ok(snippet) = tcx.sess.source_map().span_to_snippet(args_span)
-                            else {
-                                err.note(msg);
-                                return;
-                            };
-                            let (qself_sugg_span, is_self) =
-                                if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) =
-                                    &qself.kind
-                                {
-                                    // If the path segment already has type params, we want to overwrite
-                                    // them.
-                                    match &path.segments {
-                                        // `segment` is the previous to last element on the path,
-                                        // which would normally be the `enum` itself, while the last
-                                        // `_` `PathSegment` corresponds to the variant.
-                                        [
-                                            ..,
-                                            hir::PathSegment {
-                                                ident,
-                                                args,
-                                                res: Res::Def(DefKind::Enum, _),
-                                                ..
-                                            },
-                                            _,
-                                        ] => (
-                                            // We need to include the `::` in `Type::Variant::<Args>`
-                                            // to point the span to `::<Args>`, not just `<Args>`.
-                                            ident.span.shrink_to_hi().to(args
-                                                .map_or(ident.span.shrink_to_hi(), |a| a.span_ext)),
-                                            false,
-                                        ),
-                                        [segment] => (
-                                            // We need to include the `::` in `Type::Variant::<Args>`
-                                            // to point the span to `::<Args>`, not just `<Args>`.
-                                            segment.ident.span.shrink_to_hi().to(segment
-                                                .args
-                                                .map_or(segment.ident.span.shrink_to_hi(), |a| {
-                                                    a.span_ext
-                                                })),
-                                            kw::SelfUpper == segment.ident.name,
-                                        ),
-                                        _ => {
-                                            err.note(msg);
-                                            return;
-                                        }
-                                    }
-                                } else {
-                                    err.note(msg);
-                                    return;
-                                };
-                            let suggestion = vec![
-                                if is_self {
-                                    // Account for people writing `Self::Variant::<Args>`, where
-                                    // `Self` is the enum, and suggest replacing `Self` with the
-                                    // appropriate type: `Type::<Args>::Variant`.
-                                    (qself.span, format!("{type_name}{snippet}"))
-                                } else {
-                                    (qself_sugg_span, snippet)
-                                },
-                                (args_span, String::new()),
-                            ];
-                            err.multipart_suggestion_verbose(
-                                msg,
-                                suggestion,
-                                Applicability::MaybeIncorrect,
-                            );
-                        });
+                        let _ = self.prohibit_generic_args(
+                            slice::from_ref(assoc_segment).iter(),
+                            GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def },
+                        );
                         return Ok((qself_ty, DefKind::Variant, variant_def.def_id));
                     } else {
                         variant_resolution = Some(variant_def.def_id);
@@ -1624,111 +1541,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     pub fn prohibit_generic_args<'a>(
         &self,
         segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
-        extend: impl Fn(&mut Diag<'_>),
-    ) -> bool {
-        let args = segments.clone().flat_map(|segment| segment.args().args);
-
-        let (lt, ty, ct, inf) =
-            args.clone().fold((false, false, false, false), |(lt, ty, ct, inf), arg| match arg {
-                hir::GenericArg::Lifetime(_) => (true, ty, ct, inf),
-                hir::GenericArg::Type(_) => (lt, true, ct, inf),
-                hir::GenericArg::Const(_) => (lt, ty, true, inf),
-                hir::GenericArg::Infer(_) => (lt, ty, ct, true),
-            });
-        let mut emitted = false;
-        if lt || ty || ct || inf {
-            let types_and_spans: Vec<_> = segments
-                .clone()
-                .flat_map(|segment| {
-                    if segment.args().args.is_empty() {
-                        None
-                    } else {
-                        Some((
-                            match segment.res {
-                                Res::PrimTy(ty) => {
-                                    format!("{} `{}`", segment.res.descr(), ty.name())
-                                }
-                                Res::Def(_, def_id)
-                                    if let Some(name) = self.tcx().opt_item_name(def_id) =>
-                                {
-                                    format!("{} `{name}`", segment.res.descr())
-                                }
-                                Res::Err => "this type".to_string(),
-                                _ => segment.res.descr().to_string(),
-                            },
-                            segment.ident.span,
-                        ))
-                    }
-                })
-                .collect();
-            let this_type = match &types_and_spans[..] {
-                [.., _, (last, _)] => format!(
-                    "{} and {last}",
-                    types_and_spans[..types_and_spans.len() - 1]
-                        .iter()
-                        .map(|(x, _)| x.as_str())
-                        .intersperse(", ")
-                        .collect::<String>()
-                ),
-                [(only, _)] => only.to_string(),
-                [] => "this type".to_string(),
-            };
-
-            let arg_spans: Vec<Span> = args.map(|arg| arg.span()).collect();
-
-            let mut kinds = Vec::with_capacity(4);
-            if lt {
-                kinds.push("lifetime");
-            }
-            if ty {
-                kinds.push("type");
-            }
-            if ct {
-                kinds.push("const");
-            }
-            if inf {
-                kinds.push("generic");
-            }
-            let (kind, s) = match kinds[..] {
-                [.., _, last] => (
-                    format!(
-                        "{} and {last}",
-                        kinds[..kinds.len() - 1]
-                            .iter()
-                            .map(|&x| x)
-                            .intersperse(", ")
-                            .collect::<String>()
-                    ),
-                    "s",
-                ),
-                [only] => (only.to_string(), ""),
-                [] => unreachable!("expected at least one generic to prohibit"),
-            };
-            let last_span = *arg_spans.last().unwrap();
-            let span: MultiSpan = arg_spans.into();
-            let mut err = struct_span_code_err!(
-                self.tcx().dcx(),
-                span,
-                E0109,
-                "{kind} arguments are not allowed on {this_type}",
-            );
-            err.span_label(last_span, format!("{kind} argument{s} not allowed"));
-            for (what, span) in types_and_spans {
-                err.span_label(span, format!("not allowed on {what}"));
-            }
-            extend(&mut err);
-            self.set_tainted_by_errors(err.emit());
-            emitted = true;
+        err_extend: GenericsArgsErrExtend<'_>,
+    ) -> Result<(), ErrorGuaranteed> {
+        let args_visitors = segments.clone().flat_map(|segment| segment.args().args);
+        let mut result = Ok(());
+        if let Some(_) = args_visitors.clone().next() {
+            result = Err(self.report_prohibit_generics_error(
+                segments.clone(),
+                args_visitors,
+                err_extend,
+            ));
         }
 
         for segment in segments {
             // Only emit the first error to avoid overloading the user with error messages.
             if let Some(b) = segment.args().bindings.first() {
-                prohibit_assoc_item_binding(self.tcx(), b.span, None);
-                return true;
+                return Err(prohibit_assoc_item_binding(self.tcx(), b.span, None));
             }
         }
-        emitted
+
+        result
     }
 
     /// Probe path segments that are semantically allowed to have generic arguments.
@@ -1893,9 +1725,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 // Check for desugared `impl Trait`.
                 assert!(tcx.is_type_alias_impl_trait(did));
                 let item_segment = path.segments.split_last().unwrap();
-                self.prohibit_generic_args(item_segment.1.iter(), |err| {
-                    err.note("`impl Trait` types can't have type parameters");
-                });
+                let _ = self
+                    .prohibit_generic_args(item_segment.1.iter(), GenericsArgsErrExtend::OpaqueTy);
                 let args = self.lower_generic_args_of_path_segment(span, did, item_segment.0);
                 Ty::new_opaque(tcx, did, args)
             }
@@ -1908,7 +1739,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 did,
             ) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generic_args(path.segments.split_last().unwrap().1.iter(), |_| {});
+                let _ = self.prohibit_generic_args(
+                    path.segments.split_last().unwrap().1.iter(),
+                    GenericsArgsErrExtend::None,
+                );
                 self.lower_path_segment(span, did, path.segments.last().unwrap())
             }
             Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => {
@@ -1920,13 +1754,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     self.probe_generic_path_segments(path.segments, None, kind, def_id, span);
                 let indices: FxHashSet<_> =
                     generic_segments.iter().map(|GenericPathSegment(_, index)| index).collect();
-                self.prohibit_generic_args(
+                let _ = self.prohibit_generic_args(
                     path.segments.iter().enumerate().filter_map(|(index, seg)| {
                         if !indices.contains(&index) { Some(seg) } else { None }
                     }),
-                    |err| {
-                        err.note("enum variants can't have type parameters");
-                    },
+                    GenericsArgsErrExtend::DefVariant,
                 );
 
                 let GenericPathSegment(def_id, index) = generic_segments.last().unwrap();
@@ -1934,27 +1766,25 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
             Res::Def(DefKind::TyParam, def_id) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generic_args(path.segments.iter(), |err| {
-                    if let Some(span) = tcx.def_ident_span(def_id) {
-                        let name = tcx.item_name(def_id);
-                        err.span_note(span, format!("type parameter `{name}` defined here"));
-                    }
-                });
+                let _ = self.prohibit_generic_args(
+                    path.segments.iter(),
+                    GenericsArgsErrExtend::TyParam(def_id),
+                );
                 self.lower_ty_param(hir_id)
             }
             Res::SelfTyParam { .. } => {
                 // `Self` in trait or type alias.
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generic_args(path.segments.iter(), |err| {
+                let _ = self.prohibit_generic_args(
+                    path.segments.iter(),
                     if let [hir::PathSegment { args: Some(args), ident, .. }] = &path.segments {
-                        err.span_suggestion_verbose(
+                        GenericsArgsErrExtend::SelfTyParam(
                             ident.span.shrink_to_hi().to(args.span_ext),
-                            "the `Self` type doesn't accept type parameters",
-                            "",
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                });
+                        )
+                    } else {
+                        GenericsArgsErrExtend::None
+                    },
+                );
                 tcx.types.self_param
             }
             Res::SelfTyAlias { alias_to: def_id, forbid_generic, .. } => {
@@ -1962,65 +1792,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 assert_eq!(opt_self_ty, None);
                 // Try to evaluate any array length constants.
                 let ty = tcx.at(span).type_of(def_id).instantiate_identity();
-                let span_of_impl = tcx.span_of_impl(def_id);
-                self.prohibit_generic_args(path.segments.iter(), |err| {
-                    let def_id = match *ty.kind() {
-                        ty::Adt(self_def, _) => self_def.did(),
-                        _ => return,
-                    };
-
-                    let type_name = tcx.item_name(def_id);
-                    let span_of_ty = tcx.def_ident_span(def_id);
-                    let generics = tcx.generics_of(def_id).count();
-
-                    let msg = format!("`Self` is of type `{ty}`");
-                    if let (Ok(i_sp), Some(t_sp)) = (span_of_impl, span_of_ty) {
-                        let mut span: MultiSpan = vec![t_sp].into();
-                        span.push_span_label(
-                            i_sp,
-                            format!("`Self` is on type `{type_name}` in this `impl`"),
-                        );
-                        let mut postfix = "";
-                        if generics == 0 {
-                            postfix = ", which doesn't have generic parameters";
-                        }
-                        span.push_span_label(
-                            t_sp,
-                            format!("`Self` corresponds to this type{postfix}"),
-                        );
-                        err.span_note(span, msg);
-                    } else {
-                        err.note(msg);
-                    }
-                    for segment in path.segments {
-                        if let Some(args) = segment.args
-                            && segment.ident.name == kw::SelfUpper
-                        {
-                            if generics == 0 {
-                                // FIXME(estebank): we could also verify that the arguments being
-                                // work for the `enum`, instead of just looking if it takes *any*.
-                                err.span_suggestion_verbose(
-                                    segment.ident.span.shrink_to_hi().to(args.span_ext),
-                                    "the `Self` type doesn't accept type parameters",
-                                    "",
-                                    Applicability::MachineApplicable,
-                                );
-                                return;
-                            } else {
-                                err.span_suggestion_verbose(
-                                    segment.ident.span,
-                                    format!(
-                                        "the `Self` type doesn't accept type parameters, use the \
-                                        concrete type's name `{type_name}` instead if you want to \
-                                        specify its type parameters"
-                                    ),
-                                    type_name,
-                                    Applicability::MaybeIncorrect,
-                                );
-                            }
-                        }
-                    }
-                });
+                let _ = self.prohibit_generic_args(
+                    path.segments.iter(),
+                    GenericsArgsErrExtend::SelfTyAlias { def_id, span },
+                );
                 // HACK(min_const_generics): Forbid generic `Self` types
                 // here as we can't easily do that during nameres.
                 //
@@ -2061,7 +1836,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
             Res::Def(DefKind::AssocTy, def_id) => {
                 debug_assert!(path.segments.len() >= 2);
-                self.prohibit_generic_args(path.segments[..path.segments.len() - 2].iter(), |_| {});
+                let _ = self.prohibit_generic_args(
+                    path.segments[..path.segments.len() - 2].iter(),
+                    GenericsArgsErrExtend::None,
+                );
                 // HACK: until we support `<Type as ~const Trait>`, assume all of them are.
                 let constness = if tcx.has_attr(tcx.parent(def_id), sym::const_trait) {
                     ty::BoundConstness::ConstIfConst
@@ -2079,19 +1857,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
             Res::PrimTy(prim_ty) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generic_args(path.segments.iter(), |err| {
-                    let name = prim_ty.name_str();
-                    for segment in path.segments {
-                        if let Some(args) = segment.args {
-                            err.span_suggestion_verbose(
-                                segment.ident.span.shrink_to_hi().to(args.span_ext),
-                                format!("primitive type `{name}` doesn't have generic parameters"),
-                                "",
-                                Applicability::MaybeIncorrect,
-                            );
-                        }
-                    }
-                });
+                let _ = self.prohibit_generic_args(
+                    path.segments.iter(),
+                    GenericsArgsErrExtend::PrimTy(prim_ty),
+                );
                 match prim_ty {
                     hir::PrimTy::Bool => tcx.types.bool,
                     hir::PrimTy::Char => tcx.types.char,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
index b5b3a9131c5..d3ca35ba481 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
@@ -1,5 +1,4 @@
 use crate::bounds::Bounds;
-use crate::errors::TraitObjectDeclaredWithNoTraits;
 use crate::hir_ty_lowering::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_errors::{codes::*, struct_span_code_err};
@@ -86,47 +85,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
             expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
         if regular_traits.len() > 1 {
-            let first_trait = &regular_traits[0];
-            let additional_trait = &regular_traits[1];
-            let mut err = struct_span_code_err!(
-                tcx.dcx(),
-                additional_trait.bottom().1,
-                E0225,
-                "only auto traits can be used as additional traits in a trait object"
-            );
-            additional_trait.label_with_exp_info(
-                &mut err,
-                "additional non-auto trait",
-                "additional use",
-            );
-            first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use");
-            err.help(format!(
-                "consider creating a new trait with all of these as supertraits and using that \
-             trait here instead: `trait NewTrait: {} {{}}`",
-                regular_traits
-                    .iter()
-                    // FIXME: This should `print_sugared`, but also needs to integrate projection bounds...
-                    .map(|t| t.trait_ref().print_only_trait_path().to_string())
-                    .collect::<Vec<_>>()
-                    .join(" + "),
-            ));
-            err.note(
-                "auto-traits like `Send` and `Sync` are traits that have special properties; \
-             for more information on them, visit \
-             <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>",
-            );
-            self.set_tainted_by_errors(err.emit());
-        }
-
-        if regular_traits.is_empty() && auto_traits.is_empty() {
-            let trait_alias_span = trait_bounds
-                .iter()
-                .map(|&(trait_ref, _)| trait_ref.def_id())
-                .find(|&trait_ref| tcx.is_trait_alias(trait_ref))
-                .map(|trait_ref| tcx.def_span(trait_ref));
-            let reported =
-                tcx.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
-            self.set_tainted_by_errors(reported);
+            let _ = self.report_trait_object_addition_traits_error(&regular_traits);
+        } else if regular_traits.is_empty() && auto_traits.is_empty() {
+            let reported = self.report_trait_object_with_no_traits_error(span, &trait_bounds);
             return Ty::new_error(tcx, reported);
         }
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 011607bacc6..8d4d0833eef 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -11,6 +11,7 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ExprKind, GenericArg, Node, QPath};
+use rustc_hir_analysis::hir_ty_lowering::errors::GenericsArgsErrExtend;
 use rustc_hir_analysis::hir_ty_lowering::generics::{
     check_generic_arg_count_for_call, lower_generic_args,
 };
@@ -1177,11 +1178,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let indices: FxHashSet<_> =
             generic_segments.iter().map(|GenericPathSegment(_, index)| index).collect();
-        let generics_has_err = self.lowerer().prohibit_generic_args(
+        let generics_err = self.lowerer().prohibit_generic_args(
             segments.iter().enumerate().filter_map(|(index, seg)| {
                 if !indices.contains(&index) || is_alias_variant_ctor { Some(seg) } else { None }
             }),
-            |_| {},
+            GenericsArgsErrExtend::None,
         );
 
         if let Res::Local(hid) = res {
@@ -1191,7 +1192,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return (ty, res);
         }
 
-        if generics_has_err {
+        if let Err(_) = generics_err {
             // Don't try to infer type parameters when prohibited generic arguments were given.
             user_self_ty = None;
         }
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index c875d3da47e..3ab4872fffe 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -65,7 +65,7 @@ pub use self::util::{
     check_args_compatible, supertrait_def_ids, supertraits, transitive_bounds,
     transitive_bounds_that_define_assoc_item, SupertraitDefIds,
 };
-pub use self::util::{expand_trait_aliases, TraitAliasExpander};
+pub use self::util::{expand_trait_aliases, TraitAliasExpander, TraitAliasExpansionInfo};
 pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices};
 pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer};
 
diff --git a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs
index d08ca644a1c..5c96c653df5 100644
--- a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs
+++ b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs
@@ -2,6 +2,6 @@ fn main() {
     let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
 //~^ ERROR expected a pattern, found an expression
 //~| ERROR cannot find type `T` in this scope
-//~| ERROR type and const arguments are not allowed on builtin type `str`
+//~| ERROR const and type arguments are not allowed on builtin type `str`
 //~| ERROR expected unit struct, unit variant or constant, found associated function `str<, T>::as_bytes`
 }
diff --git a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr
index 19d4ac713ce..d62c019a1e1 100644
--- a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr
+++ b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr
@@ -10,11 +10,11 @@ error[E0412]: cannot find type `T` in this scope
 LL |     let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
    |                                                       ^ not found in this scope
 
-error[E0109]: type and const arguments are not allowed on builtin type `str`
+error[E0109]: const and type arguments are not allowed on builtin type `str`
   --> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:15
    |
 LL |     let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
-   |         ---   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  ^ type and const arguments not allowed
+   |         ---   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  ^ const and type arguments not allowed
    |         |
    |         not allowed on builtin type `str`
    |