about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2022-05-27 19:53:31 -0700
committerEsteban Küber <esteban@kuber.com.ar>2022-06-01 10:41:50 -0700
commit9b2d80a197453001f9acd40020c1db6c0178c7fe (patch)
tree876dc00b0a3a0aacea42246bf805ff2a4dd9b178
parentf023b920b195477b65945550a2c5949ca7e7cf3e (diff)
downloadrust-9b2d80a197453001f9acd40020c1db6c0178c7fe.tar.gz
rust-9b2d80a197453001f9acd40020c1db6c0178c7fe.zip
Provide more context when denying invalid type params
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs169
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs1
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs7
-rw-r--r--src/test/ui/error-codes/E0109.stderr6
-rw-r--r--src/test/ui/error-codes/E0110.stderr6
-rw-r--r--src/test/ui/structs/struct-path-self.stderr32
-rw-r--r--src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr122
-rw-r--r--src/test/ui/type/issue-91268.stderr6
-rw-r--r--src/test/ui/typeck/prim-with-args.fixed28
-rw-r--r--src/test/ui/typeck/prim-with-args.rs45
-rw-r--r--src/test/ui/typeck/prim-with-args.stderr246
-rw-r--r--src/test/ui/usize-generic-argument-parent.stderr6
12 files changed, 564 insertions, 110 deletions
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 492e9609f96..56a4025f297 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -30,7 +30,7 @@ use rustc_middle::ty::{self, Const, DefIdTree, EarlyBinder, Ty, TyCtxt, TypeFold
 use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
 use rustc_span::edition::Edition;
 use rustc_span::lev_distance::find_best_match_for_name;
-use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::abi;
 use rustc_trait_selection::traits;
@@ -653,7 +653,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             span, item_def_id, item_segment
         );
         if tcx.generics_of(item_def_id).params.is_empty() {
-            self.prohibit_generics(slice::from_ref(item_segment).iter());
+            self.prohibit_generics(slice::from_ref(item_segment).iter(), |_| {});
 
             parent_substs
         } else {
@@ -681,7 +681,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         trait_ref: &hir::TraitRef<'_>,
         self_ty: Ty<'tcx>,
     ) -> ty::TraitRef<'tcx> {
-        self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter());
+        self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
 
         self.ast_path_to_mono_trait_ref(
             trait_ref.path.span,
@@ -784,7 +784,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let args = trait_segment.args();
         let infer_args = trait_segment.infer_args;
 
-        self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter());
+        self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
         self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
 
         self.instantiate_poly_trait_ref_inner(
@@ -1776,12 +1776,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         hir_ref_id: hir::HirId,
         span: Span,
         qself_ty: Ty<'tcx>,
-        qself_res: Res,
+        qself: &hir::Ty<'_>,
         assoc_segment: &hir::PathSegment<'_>,
         permit_variants: bool,
     ) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
         let tcx = self.tcx();
         let assoc_ident = assoc_segment.ident;
+        let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = qself.kind {
+            path.res
+        } else {
+            Res::Err
+        };
 
         debug!("associated_path_to_ty: {:?}::{}", qself_ty, assoc_ident);
 
@@ -1796,7 +1801,55 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 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_generics(slice::from_ref(assoc_segment).iter());
+                        self.prohibit_generics(slice::from_ref(assoc_segment).iter(), |err| {
+                            err.note("enum variants can't have type parameters");
+                            let type_name = tcx.opt_item_name(adt_def.did());
+                            let the_enum = type_name.map(|n| format!("enum `{n}`")).unwrap_or_else(|| "the enum".to_string());
+                            let msg = format!("you might have meant to specity type parameters on {the_enum}");
+                            let Some(args) = assoc_segment.args else { return; };
+                            let args_span = assoc_segment.ident.span.shrink_to_hi().to(args.span_ext);
+                            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(_, ref path)) = qself.kind {
+                                // If the path segment already has type params, we want to overwrite
+                                // them.
+                                match &path.segments[..] {
+                                    [.., segment, _] => (
+                                        segment.ident.span.shrink_to_hi().to(segment.args.map_or(
+                                            segment.ident.span.shrink_to_hi(),
+                                            |a| a.span_ext)),
+                                        false,
+                                    ),
+                                    [segment] => (
+                                        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,
+                                    ),
+                                    _ => unreachable!(),
+                                }
+                            } else {
+                                err.note(&msg);
+                                return;
+                            };
+                            let Some(type_name) = type_name else {
+                                err.note(&msg);
+                                return;
+                            };
+                            let suggestion = vec![
+                                if is_self {
+                                    // Account for people writing `Self::Variant::<Args>`, where
+                                    // `Self` is the enum.
+                                    (qself.span, format!("{type_name}{snippet}"))
+                                } else {
+                                    (qself_sugg_span, snippet)
+                                },
+                                (args_span, String::new()),
+                            ];
+                            err.multipart_suggestion_verbose(&msg, suggestion, Applicability::MaybeIncorrect);
+                        });
                         return Ok((qself_ty, DefKind::Variant, variant_def.def_id));
                     } else {
                         variant_resolution = Some(variant_def.def_id);
@@ -2017,9 +2070,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         self.normalize_ty(span, tcx.mk_projection(item_def_id, item_substs))
     }
 
-    pub fn prohibit_generics<'a, T: Iterator<Item = &'a hir::PathSegment<'a>> + Clone>(
+    pub fn prohibit_generics<'a>(
         &self,
-        segments: T,
+        segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
+        extend: impl Fn(&mut DiagnosticBuilder<'tcx, ErrorGuaranteed>),
     ) -> bool {
         let args = segments.clone().flat_map(|segment| segment.args().args);
 
@@ -2078,6 +2132,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 "{kind} arguments are not allowed for this type",
             );
             err.span_label(last_span, format!("{kind} argument{s} not allowed"));
+            extend(&mut err);
             err.emit();
             emitted = true;
         }
@@ -2239,7 +2294,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 // Check for desugared `impl Trait`.
                 assert!(ty::is_impl_trait_defn(tcx, did).is_none());
                 let item_segment = path.segments.split_last().unwrap();
-                self.prohibit_generics(item_segment.1.iter());
+                self.prohibit_generics(item_segment.1.iter(), |err| {
+                    err.note("`impl Trait` types can't have type parameters");
+                });
                 let substs = self.ast_path_substs_for_ty(span, did, item_segment.0);
                 self.normalize_ty(span, tcx.mk_opaque(did, substs))
             }
@@ -2252,7 +2309,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 did,
             ) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generics(path.segments.split_last().unwrap().1.iter());
+                self.prohibit_generics(path.segments.split_last().unwrap().1.iter(), |_| {});
                 self.ast_path_to_ty(span, did, path.segments.last().unwrap())
             }
             Res::Def(kind @ DefKind::Variant, def_id) if permit_variants => {
@@ -2264,18 +2321,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     self.def_ids_for_value_path_segments(path.segments, None, kind, def_id);
                 let generic_segs: FxHashSet<_> =
                     path_segs.iter().map(|PathSeg(_, index)| index).collect();
-                self.prohibit_generics(path.segments.iter().enumerate().filter_map(
-                    |(index, seg)| {
+                self.prohibit_generics(
+                    path.segments.iter().enumerate().filter_map(|(index, seg)| {
                         if !generic_segs.contains(&index) { Some(seg) } else { None }
+                    }),
+                    |err| {
+                        err.note("enum variants can't have type parameters");
                     },
-                ));
+                );
 
                 let PathSeg(def_id, index) = path_segs.last().unwrap();
                 self.ast_path_to_ty(span, *def_id, &path.segments[*index])
             }
             Res::Def(DefKind::TyParam, def_id) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generics(path.segments.iter());
+                self.prohibit_generics(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 def_id = def_id.expect_local();
                 let item_def_id = tcx.hir().ty_param_owner(def_id);
@@ -2286,15 +2351,63 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             Res::SelfTy { trait_: Some(_), alias_to: None } => {
                 // `Self` in trait or type alias.
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generics(path.segments.iter());
+                self.prohibit_generics(path.segments.iter(), |err| {
+                    if let [hir::PathSegment { args: Some(args), ident, .. }] = &path.segments[..] {
+                        err.span_suggestion_verbose(
+                            ident.span.shrink_to_hi().to(args.span_ext),
+                            "the `Self` type doesn't accept type parameters",
+                            String::new(),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                });
                 tcx.types.self_param
             }
             Res::SelfTy { trait_: _, alias_to: Some((def_id, forbid_generic)) } => {
                 // `Self` in impl (we know the concrete type).
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generics(path.segments.iter());
                 // Try to evaluate any array length constants.
                 let ty = tcx.at(span).type_of(def_id);
+                let span_of_impl = tcx.span_of_impl(def_id);
+                // TODO: confirm that `def_id`'s type accepts type params at all before suggesting
+                // using that instead.
+                self.prohibit_generics(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 msg = format!("the `Self` type is `{ty}`");
+                    if let (Ok(i_sp), Some(t_sp)) = (span_of_impl, span_of_ty) {
+                        let i_sp = tcx.sess.source_map().guess_head_span(i_sp);
+                        let mut span: MultiSpan = vec![t_sp].into();
+                        span.push_span_label(
+                            i_sp,
+                            &format!("`Self` is `{type_name}` in this `impl`"),
+                        );
+                        span.push_span_label(t_sp, "`Self` corresponds to this type");
+                        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 {
+                            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.to_string(),
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+                    }
+                });
                 // HACK(min_const_generics): Forbid generic `Self` types
                 // here as we can't easily do that during nameres.
                 //
@@ -2334,7 +2447,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
             Res::Def(DefKind::AssocTy, def_id) => {
                 debug_assert!(path.segments.len() >= 2);
-                self.prohibit_generics(path.segments[..path.segments.len() - 2].iter());
+                self.prohibit_generics(path.segments[..path.segments.len() - 2].iter(), |_| {});
                 self.qpath_to_ty(
                     span,
                     opt_self_ty,
@@ -2345,7 +2458,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
             Res::PrimTy(prim_ty) => {
                 assert_eq!(opt_self_ty, None);
-                self.prohibit_generics(path.segments.iter());
+                self.prohibit_generics(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 type parameters"),
+                                String::new(),
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+                    }
+                });
                 match prim_ty {
                     hir::PrimTy::Bool => tcx.types.bool,
                     hir::PrimTy::Char => tcx.types.char,
@@ -2436,13 +2561,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
                 debug!(?qself, ?segment);
                 let ty = self.ast_ty_to_ty_inner(qself, false, true);
-
-                let res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = qself.kind {
-                    path.res
-                } else {
-                    Res::Err
-                };
-                self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, res, segment, false)
+                self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, qself, segment, false)
                     .map(|(ty, _, _)| ty)
                     .unwrap_or_else(|_| tcx.ty_error())
             }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index ac2dc6522ad..c28c041e78d 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -1228,6 +1228,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     None
                 }
             }),
+            |_| {},
         );
 
         if let Res::Local(hid) = res {
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index 34cc02f180b..83afbfa54b1 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -1564,13 +1564,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             QPath::TypeRelative(ref qself, ref segment) => {
                 let ty = self.to_ty(qself);
 
-                let res = if let hir::TyKind::Path(QPath::Resolved(_, ref path)) = qself.kind {
-                    path.res
-                } else {
-                    Res::Err
-                };
                 let result = <dyn AstConv<'_>>::associated_path_to_ty(
-                    self, hir_id, path_span, ty, res, segment, true,
+                    self, hir_id, path_span, ty, qself, segment, true,
                 );
                 let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error());
                 let result = result.map(|(_, kind, def_id)| (kind, def_id));
diff --git a/src/test/ui/error-codes/E0109.stderr b/src/test/ui/error-codes/E0109.stderr
index 577e286fcc6..cb12bcd1ba4 100644
--- a/src/test/ui/error-codes/E0109.stderr
+++ b/src/test/ui/error-codes/E0109.stderr
@@ -3,6 +3,12 @@ error[E0109]: type arguments are not allowed for this type
    |
 LL | type X = u32<i32>;
    |              ^^^ type argument not allowed
+   |
+help: primitive type `u32` doesn't have type parameters
+   |
+LL - type X = u32<i32>;
+LL + type X = u32;
+   | 
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0110.stderr b/src/test/ui/error-codes/E0110.stderr
index b0221318087..5140f72b3ce 100644
--- a/src/test/ui/error-codes/E0110.stderr
+++ b/src/test/ui/error-codes/E0110.stderr
@@ -3,6 +3,12 @@ error[E0109]: lifetime arguments are not allowed for this type
    |
 LL | type X = u32<'static>;
    |              ^^^^^^^ lifetime argument not allowed
+   |
+help: primitive type `u32` doesn't have type parameters
+   |
+LL - type X = u32<'static>;
+LL + type X = u32;
+   | 
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/structs/struct-path-self.stderr b/src/test/ui/structs/struct-path-self.stderr
index 693ed35cbc9..f8b85559db8 100644
--- a/src/test/ui/structs/struct-path-self.stderr
+++ b/src/test/ui/structs/struct-path-self.stderr
@@ -9,6 +9,12 @@ error[E0109]: type arguments are not allowed for this type
    |
 LL |         let z = Self::<u8> {};
    |                        ^^ type argument not allowed
+   |
+help: the `Self` type doesn't accept type parameters
+   |
+LL -         let z = Self::<u8> {};
+LL +         let z = Self {};
+   | 
 
 error[E0071]: expected struct, variant or union type, found type parameter `Self`
   --> $DIR/struct-path-self.rs:7:17
@@ -27,12 +33,38 @@ error[E0109]: type arguments are not allowed for this type
    |
 LL |         let z = Self::<u8> {};
    |                        ^^ type argument not allowed
+   |
+note: the `Self` type is `S`
+  --> $DIR/struct-path-self.rs:1:8
+   |
+LL | struct S;
+   |        ^ `Self` corresponds to this type
+...
+LL | impl Tr for S {
+   | ------------- `Self` is `S` in this `impl`
+help: the `Self` type doesn't accept type parameters, use the concrete type's name `S` instead if you want to specify its type parameters
+   |
+LL |         let z = S::<u8> {};
+   |                 ~
 
 error[E0109]: type arguments are not allowed for this type
   --> $DIR/struct-path-self.rs:30:24
    |
 LL |         let z = Self::<u8> {};
    |                        ^^ type argument not allowed
+   |
+note: the `Self` type is `S`
+  --> $DIR/struct-path-self.rs:1:8
+   |
+LL | struct S;
+   |        ^ `Self` corresponds to this type
+...
+LL | impl S {
+   | ------ `Self` is `S` in this `impl`
+help: the `Self` type doesn't accept type parameters, use the concrete type's name `S` instead if you want to specify its type parameters
+   |
+LL |         let z = S::<u8> {};
+   |                 ~
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr b/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr
index 115ecb01376..a0df5c416b2 100644
--- a/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr
+++ b/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr
@@ -28,6 +28,19 @@ error[E0109]: type arguments are not allowed for this type
    |
 LL |         Self::<()>::TSVariant(());
    |                ^^ type argument not allowed
+   |
+note: the `Self` type is `Enum<T>`
+  --> $DIR/enum-variant-generic-args.rs:7:6
+   |
+LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
+   |      ^^^^ `Self` corresponds to this type
+...
+LL | impl<T> Enum<T> {
+   | --------------- `Self` is `Enum` in this `impl`
+help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
+   |
+LL |         Enum::<()>::TSVariant(());
+   |         ~~~~
 
 error[E0308]: mismatched types
   --> $DIR/enum-variant-generic-args.rs:17:31
@@ -53,6 +66,19 @@ error[E0109]: type arguments are not allowed for this type
    |
 LL |         Self::<()>::TSVariant::<()>(());
    |                ^^ type argument not allowed
+   |
+note: the `Self` type is `Enum<T>`
+  --> $DIR/enum-variant-generic-args.rs:7:6
+   |
+LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
+   |      ^^^^ `Self` corresponds to this type
+...
+LL | impl<T> Enum<T> {
+   | --------------- `Self` is `Enum` in this `impl`
+help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
+   |
+LL |         Enum::<()>::TSVariant::<()>(());
+   |         ~~~~
 
 error[E0109]: type arguments are not allowed for this type
   --> $DIR/enum-variant-generic-args.rs:20:33
@@ -77,6 +103,13 @@ error[E0109]: type arguments are not allowed for this type
    |
 LL |         Self::SVariant::<()> { v: () };
    |                          ^^ type argument not allowed
+   |
+   = note: enum variants can't have type parameters
+help: you might have meant to specity type parameters on enum `Enum`
+   |
+LL -         Self::SVariant::<()> { v: () };
+LL +         Enum::<()>::SVariant { v: () };
+   | 
 
 error[E0308]: mismatched types
   --> $DIR/enum-variant-generic-args.rs:28:35
@@ -95,6 +128,19 @@ error[E0109]: type arguments are not allowed for this type
    |
 LL |         Self::<()>::SVariant { v: () };
    |                ^^ type argument not allowed
+   |
+note: the `Self` type is `Enum<T>`
+  --> $DIR/enum-variant-generic-args.rs:7:6
+   |
+LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
+   |      ^^^^ `Self` corresponds to this type
+...
+LL | impl<T> Enum<T> {
+   | --------------- `Self` is `Enum` in this `impl`
+help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
+   |
+LL |         Enum::<()>::SVariant { v: () };
+   |         ~~~~
 
 error[E0308]: mismatched types
   --> $DIR/enum-variant-generic-args.rs:31:35
@@ -113,12 +159,32 @@ error[E0109]: type arguments are not allowed for this type
    |
 LL |         Self::<()>::SVariant::<()> { v: () };
    |                ^^ type argument not allowed
+   |
+note: the `Self` type is `Enum<T>`
+  --> $DIR/enum-variant-generic-args.rs:7:6
+   |
+LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
+   |      ^^^^ `Self` corresponds to this type
+...
+LL | impl<T> Enum<T> {
+   | --------------- `Self` is `Enum` in this `impl`
+help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
+   |
+LL |         Enum::<()>::SVariant::<()> { v: () };
+   |         ~~~~
 
 error[E0109]: type arguments are not allowed for this type
   --> $DIR/enum-variant-generic-args.rs:34:32
    |
 LL |         Self::<()>::SVariant::<()> { v: () };
    |                                ^^ type argument not allowed
+   |
+   = note: enum variants can't have type parameters
+help: you might have meant to specity type parameters on enum `Enum`
+   |
+LL -         Self::<()>::SVariant::<()> { v: () };
+LL +         Enum::<()>::SVariant { v: () };
+   | 
 
 error[E0308]: mismatched types
   --> $DIR/enum-variant-generic-args.rs:34:41
@@ -143,12 +209,38 @@ error[E0109]: type arguments are not allowed for this type
    |
 LL |         Self::<()>::UVariant;
    |                ^^ type argument not allowed
+   |
+note: the `Self` type is `Enum<T>`
+  --> $DIR/enum-variant-generic-args.rs:7:6
+   |
+LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
+   |      ^^^^ `Self` corresponds to this type
+...
+LL | impl<T> Enum<T> {
+   | --------------- `Self` is `Enum` in this `impl`
+help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
+   |
+LL |         Enum::<()>::UVariant;
+   |         ~~~~
 
 error[E0109]: type arguments are not allowed for this type
   --> $DIR/enum-variant-generic-args.rs:45:16
    |
 LL |         Self::<()>::UVariant::<()>;
    |                ^^ type argument not allowed
+   |
+note: the `Self` type is `Enum<T>`
+  --> $DIR/enum-variant-generic-args.rs:7:6
+   |
+LL | enum Enum<T> { TSVariant(T), SVariant { v: T }, UVariant }
+   |      ^^^^ `Self` corresponds to this type
+...
+LL | impl<T> Enum<T> {
+   | --------------- `Self` is `Enum` in this `impl`
+help: the `Self` type doesn't accept type parameters, use the concrete type's name `Enum` instead if you want to specify its type parameters
+   |
+LL |         Enum::<()>::UVariant::<()>;
+   |         ~~~~
 
 error[E0109]: type arguments are not allowed for this type
   --> $DIR/enum-variant-generic-args.rs:45:32
@@ -219,24 +311,47 @@ error[E0109]: type arguments are not allowed for this type
    |
 LL |     Enum::<()>::SVariant::<()> { v: () };
    |                            ^^ type argument not allowed
+   |
+   = note: enum variants can't have type parameters
 
 error[E0109]: type arguments are not allowed for this type
   --> $DIR/enum-variant-generic-args.rs:75:23
    |
 LL |     Alias::SVariant::<()> { v: () };
    |                       ^^ type argument not allowed
+   |
+   = note: enum variants can't have type parameters
+help: you might have meant to specity type parameters on enum `Enum`
+   |
+LL -     Alias::SVariant::<()> { v: () };
+LL +     Alias::<()>::SVariant { v: () };
+   | 
 
 error[E0109]: type arguments are not allowed for this type
   --> $DIR/enum-variant-generic-args.rs:77:29
    |
 LL |     Alias::<()>::SVariant::<()> { v: () };
    |                             ^^ type argument not allowed
+   |
+   = note: enum variants can't have type parameters
+help: you might have meant to specity type parameters on enum `Enum`
+   |
+LL -     Alias::<()>::SVariant::<()> { v: () };
+LL +     Alias::<()>::SVariant { v: () };
+   | 
 
 error[E0109]: type arguments are not allowed for this type
   --> $DIR/enum-variant-generic-args.rs:80:28
    |
 LL |     AliasFixed::SVariant::<()> { v: () };
    |                            ^^ type argument not allowed
+   |
+   = note: enum variants can't have type parameters
+help: you might have meant to specity type parameters on enum `Enum`
+   |
+LL -     AliasFixed::SVariant::<()> { v: () };
+LL +     AliasFixed::<()>::SVariant { v: () };
+   | 
 
 error[E0107]: this type alias takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/enum-variant-generic-args.rs:82:5
@@ -271,6 +386,13 @@ error[E0109]: type arguments are not allowed for this type
    |
 LL |     AliasFixed::<()>::SVariant::<()> { v: () };
    |                                  ^^ type argument not allowed
+   |
+   = note: enum variants can't have type parameters
+help: you might have meant to specity type parameters on enum `Enum`
+   |
+LL -     AliasFixed::<()>::SVariant::<()> { v: () };
+LL +     AliasFixed::<()>::SVariant { v: () };
+   | 
 
 error[E0109]: type arguments are not allowed for this type
   --> $DIR/enum-variant-generic-args.rs:90:28
diff --git a/src/test/ui/type/issue-91268.stderr b/src/test/ui/type/issue-91268.stderr
index 2fe6ba6248c..9e86fd3aa7d 100644
--- a/src/test/ui/type/issue-91268.stderr
+++ b/src/test/ui/type/issue-91268.stderr
@@ -35,6 +35,12 @@ error[E0109]: type arguments are not allowed for this type
    |
 LL |     0: u8(ţ
    |           ^ type argument not allowed
+   |
+help: primitive type `u8` doesn't have type parameters
+   |
+LL -     0: u8(ţ
+LL +     0: u8
+   | 
 
 error[E0308]: mismatched types
   --> $DIR/issue-91268.rs:9:5
diff --git a/src/test/ui/typeck/prim-with-args.fixed b/src/test/ui/typeck/prim-with-args.fixed
new file mode 100644
index 00000000000..0fd4a0f984e
--- /dev/null
+++ b/src/test/ui/typeck/prim-with-args.fixed
@@ -0,0 +1,28 @@
+// run-rustfix
+fn main() {
+
+let _x: isize; //~ ERROR type arguments are not allowed for this type
+let _x: i8; //~ ERROR type arguments are not allowed for this type
+let _x: i16; //~ ERROR type arguments are not allowed for this type
+let _x: i32; //~ ERROR type arguments are not allowed for this type
+let _x: i64; //~ ERROR type arguments are not allowed for this type
+let _x: usize; //~ ERROR type arguments are not allowed for this type
+let _x: u8; //~ ERROR type arguments are not allowed for this type
+let _x: u16; //~ ERROR type arguments are not allowed for this type
+let _x: u32; //~ ERROR type arguments are not allowed for this type
+let _x: u64; //~ ERROR type arguments are not allowed for this type
+let _x: char; //~ ERROR type arguments are not allowed for this type
+
+let _x: isize; //~ ERROR lifetime arguments are not allowed for this type
+let _x: i8; //~ ERROR lifetime arguments are not allowed for this type
+let _x: i16; //~ ERROR lifetime arguments are not allowed for this type
+let _x: i32; //~ ERROR lifetime arguments are not allowed for this type
+let _x: i64; //~ ERROR lifetime arguments are not allowed for this type
+let _x: usize; //~ ERROR lifetime arguments are not allowed for this type
+let _x: u8; //~ ERROR lifetime arguments are not allowed for this type
+let _x: u16; //~ ERROR lifetime arguments are not allowed for this type
+let _x: u32; //~ ERROR lifetime arguments are not allowed for this type
+let _x: u64; //~ ERROR lifetime arguments are not allowed for this type
+let _x: char; //~ ERROR lifetime arguments are not allowed for this type
+
+}
diff --git a/src/test/ui/typeck/prim-with-args.rs b/src/test/ui/typeck/prim-with-args.rs
index e5beaca6abb..a21fe69dc6a 100644
--- a/src/test/ui/typeck/prim-with-args.rs
+++ b/src/test/ui/typeck/prim-with-args.rs
@@ -1,27 +1,28 @@
+// run-rustfix
 fn main() {
 
-let x: isize<isize>; //~ ERROR type arguments are not allowed for this type
-let x: i8<isize>; //~ ERROR type arguments are not allowed for this type
-let x: i16<isize>; //~ ERROR type arguments are not allowed for this type
-let x: i32<isize>; //~ ERROR type arguments are not allowed for this type
-let x: i64<isize>; //~ ERROR type arguments are not allowed for this type
-let x: usize<isize>; //~ ERROR type arguments are not allowed for this type
-let x: u8<isize>; //~ ERROR type arguments are not allowed for this type
-let x: u16<isize>; //~ ERROR type arguments are not allowed for this type
-let x: u32<isize>; //~ ERROR type arguments are not allowed for this type
-let x: u64<isize>; //~ ERROR type arguments are not allowed for this type
-let x: char<isize>; //~ ERROR type arguments are not allowed for this type
+let _x: isize<isize>; //~ ERROR type arguments are not allowed for this type
+let _x: i8<isize>; //~ ERROR type arguments are not allowed for this type
+let _x: i16<isize>; //~ ERROR type arguments are not allowed for this type
+let _x: i32<isize>; //~ ERROR type arguments are not allowed for this type
+let _x: i64<isize>; //~ ERROR type arguments are not allowed for this type
+let _x: usize<isize>; //~ ERROR type arguments are not allowed for this type
+let _x: u8<isize>; //~ ERROR type arguments are not allowed for this type
+let _x: u16<isize>; //~ ERROR type arguments are not allowed for this type
+let _x: u32<isize>; //~ ERROR type arguments are not allowed for this type
+let _x: u64<isize>; //~ ERROR type arguments are not allowed for this type
+let _x: char<isize>; //~ ERROR type arguments are not allowed for this type
 
-let x: isize<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: i8<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: i16<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: i32<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: i64<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: usize<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: u8<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: u16<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: u32<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: u64<'static>; //~ ERROR lifetime arguments are not allowed for this type
-let x: char<'static>; //~ ERROR lifetime arguments are not allowed for this type
+let _x: isize<'static>; //~ ERROR lifetime arguments are not allowed for this type
+let _x: i8<'static>; //~ ERROR lifetime arguments are not allowed for this type
+let _x: i16<'static>; //~ ERROR lifetime arguments are not allowed for this type
+let _x: i32<'static>; //~ ERROR lifetime arguments are not allowed for this type
+let _x: i64<'static>; //~ ERROR lifetime arguments are not allowed for this type
+let _x: usize<'static>; //~ ERROR lifetime arguments are not allowed for this type
+let _x: u8<'static>; //~ ERROR lifetime arguments are not allowed for this type
+let _x: u16<'static>; //~ ERROR lifetime arguments are not allowed for this type
+let _x: u32<'static>; //~ ERROR lifetime arguments are not allowed for this type
+let _x: u64<'static>; //~ ERROR lifetime arguments are not allowed for this type
+let _x: char<'static>; //~ ERROR lifetime arguments are not allowed for this type
 
 }
diff --git a/src/test/ui/typeck/prim-with-args.stderr b/src/test/ui/typeck/prim-with-args.stderr
index 4bde981e7f2..d7c32cf8ecf 100644
--- a/src/test/ui/typeck/prim-with-args.stderr
+++ b/src/test/ui/typeck/prim-with-args.stderr
@@ -1,134 +1,266 @@
 error[E0109]: type arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:3:14
+  --> $DIR/prim-with-args.rs:4:15
    |
-LL | let x: isize<isize>;
-   |              ^^^^^ type argument not allowed
-
-error[E0109]: type arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:4:11
+LL | let _x: isize<isize>;
+   |               ^^^^^ type argument not allowed
    |
-LL | let x: i8<isize>;
-   |           ^^^^^ type argument not allowed
+help: primitive type `isize` doesn't have type parameters
+   |
+LL - let _x: isize<isize>;
+LL + let _x: isize;
+   | 
 
 error[E0109]: type arguments are not allowed for this type
   --> $DIR/prim-with-args.rs:5:12
    |
-LL | let x: i16<isize>;
+LL | let _x: i8<isize>;
    |            ^^^^^ type argument not allowed
+   |
+help: primitive type `i8` doesn't have type parameters
+   |
+LL - let _x: i8<isize>;
+LL + let _x: i8;
+   | 
 
 error[E0109]: type arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:6:12
+  --> $DIR/prim-with-args.rs:6:13
    |
-LL | let x: i32<isize>;
-   |            ^^^^^ type argument not allowed
+LL | let _x: i16<isize>;
+   |             ^^^^^ type argument not allowed
+   |
+help: primitive type `i16` doesn't have type parameters
+   |
+LL - let _x: i16<isize>;
+LL + let _x: i16;
+   | 
 
 error[E0109]: type arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:7:12
+  --> $DIR/prim-with-args.rs:7:13
    |
-LL | let x: i64<isize>;
-   |            ^^^^^ type argument not allowed
+LL | let _x: i32<isize>;
+   |             ^^^^^ type argument not allowed
+   |
+help: primitive type `i32` doesn't have type parameters
+   |
+LL - let _x: i32<isize>;
+LL + let _x: i32;
+   | 
 
 error[E0109]: type arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:8:14
+  --> $DIR/prim-with-args.rs:8:13
    |
-LL | let x: usize<isize>;
-   |              ^^^^^ type argument not allowed
+LL | let _x: i64<isize>;
+   |             ^^^^^ type argument not allowed
+   |
+help: primitive type `i64` doesn't have type parameters
+   |
+LL - let _x: i64<isize>;
+LL + let _x: i64;
+   | 
 
 error[E0109]: type arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:9:11
+  --> $DIR/prim-with-args.rs:9:15
+   |
+LL | let _x: usize<isize>;
+   |               ^^^^^ type argument not allowed
    |
-LL | let x: u8<isize>;
-   |           ^^^^^ type argument not allowed
+help: primitive type `usize` doesn't have type parameters
+   |
+LL - let _x: usize<isize>;
+LL + let _x: usize;
+   | 
 
 error[E0109]: type arguments are not allowed for this type
   --> $DIR/prim-with-args.rs:10:12
    |
-LL | let x: u16<isize>;
+LL | let _x: u8<isize>;
    |            ^^^^^ type argument not allowed
+   |
+help: primitive type `u8` doesn't have type parameters
+   |
+LL - let _x: u8<isize>;
+LL + let _x: u8;
+   | 
 
 error[E0109]: type arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:11:12
+  --> $DIR/prim-with-args.rs:11:13
    |
-LL | let x: u32<isize>;
-   |            ^^^^^ type argument not allowed
+LL | let _x: u16<isize>;
+   |             ^^^^^ type argument not allowed
+   |
+help: primitive type `u16` doesn't have type parameters
+   |
+LL - let _x: u16<isize>;
+LL + let _x: u16;
+   | 
 
 error[E0109]: type arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:12:12
+  --> $DIR/prim-with-args.rs:12:13
    |
-LL | let x: u64<isize>;
-   |            ^^^^^ type argument not allowed
+LL | let _x: u32<isize>;
+   |             ^^^^^ type argument not allowed
+   |
+help: primitive type `u32` doesn't have type parameters
+   |
+LL - let _x: u32<isize>;
+LL + let _x: u32;
+   | 
 
 error[E0109]: type arguments are not allowed for this type
   --> $DIR/prim-with-args.rs:13:13
    |
-LL | let x: char<isize>;
+LL | let _x: u64<isize>;
    |             ^^^^^ type argument not allowed
+   |
+help: primitive type `u64` doesn't have type parameters
+   |
+LL - let _x: u64<isize>;
+LL + let _x: u64;
+   | 
 
-error[E0109]: lifetime arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:15:14
+error[E0109]: type arguments are not allowed for this type
+  --> $DIR/prim-with-args.rs:14:14
    |
-LL | let x: isize<'static>;
-   |              ^^^^^^^ lifetime argument not allowed
+LL | let _x: char<isize>;
+   |              ^^^^^ type argument not allowed
+   |
+help: primitive type `char` doesn't have type parameters
+   |
+LL - let _x: char<isize>;
+LL + let _x: char;
+   | 
 
 error[E0109]: lifetime arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:16:11
+  --> $DIR/prim-with-args.rs:16:15
+   |
+LL | let _x: isize<'static>;
+   |               ^^^^^^^ lifetime argument not allowed
+   |
+help: primitive type `isize` doesn't have type parameters
    |
-LL | let x: i8<'static>;
-   |           ^^^^^^^ lifetime argument not allowed
+LL - let _x: isize<'static>;
+LL + let _x: isize;
+   | 
 
 error[E0109]: lifetime arguments are not allowed for this type
   --> $DIR/prim-with-args.rs:17:12
    |
-LL | let x: i16<'static>;
+LL | let _x: i8<'static>;
    |            ^^^^^^^ lifetime argument not allowed
+   |
+help: primitive type `i8` doesn't have type parameters
+   |
+LL - let _x: i8<'static>;
+LL + let _x: i8;
+   | 
 
 error[E0109]: lifetime arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:18:12
+  --> $DIR/prim-with-args.rs:18:13
    |
-LL | let x: i32<'static>;
-   |            ^^^^^^^ lifetime argument not allowed
+LL | let _x: i16<'static>;
+   |             ^^^^^^^ lifetime argument not allowed
+   |
+help: primitive type `i16` doesn't have type parameters
+   |
+LL - let _x: i16<'static>;
+LL + let _x: i16;
+   | 
 
 error[E0109]: lifetime arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:19:12
+  --> $DIR/prim-with-args.rs:19:13
    |
-LL | let x: i64<'static>;
-   |            ^^^^^^^ lifetime argument not allowed
+LL | let _x: i32<'static>;
+   |             ^^^^^^^ lifetime argument not allowed
+   |
+help: primitive type `i32` doesn't have type parameters
+   |
+LL - let _x: i32<'static>;
+LL + let _x: i32;
+   | 
 
 error[E0109]: lifetime arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:20:14
+  --> $DIR/prim-with-args.rs:20:13
    |
-LL | let x: usize<'static>;
-   |              ^^^^^^^ lifetime argument not allowed
+LL | let _x: i64<'static>;
+   |             ^^^^^^^ lifetime argument not allowed
+   |
+help: primitive type `i64` doesn't have type parameters
+   |
+LL - let _x: i64<'static>;
+LL + let _x: i64;
+   | 
 
 error[E0109]: lifetime arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:21:11
+  --> $DIR/prim-with-args.rs:21:15
+   |
+LL | let _x: usize<'static>;
+   |               ^^^^^^^ lifetime argument not allowed
+   |
+help: primitive type `usize` doesn't have type parameters
    |
-LL | let x: u8<'static>;
-   |           ^^^^^^^ lifetime argument not allowed
+LL - let _x: usize<'static>;
+LL + let _x: usize;
+   | 
 
 error[E0109]: lifetime arguments are not allowed for this type
   --> $DIR/prim-with-args.rs:22:12
    |
-LL | let x: u16<'static>;
+LL | let _x: u8<'static>;
    |            ^^^^^^^ lifetime argument not allowed
+   |
+help: primitive type `u8` doesn't have type parameters
+   |
+LL - let _x: u8<'static>;
+LL + let _x: u8;
+   | 
 
 error[E0109]: lifetime arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:23:12
+  --> $DIR/prim-with-args.rs:23:13
    |
-LL | let x: u32<'static>;
-   |            ^^^^^^^ lifetime argument not allowed
+LL | let _x: u16<'static>;
+   |             ^^^^^^^ lifetime argument not allowed
+   |
+help: primitive type `u16` doesn't have type parameters
+   |
+LL - let _x: u16<'static>;
+LL + let _x: u16;
+   | 
 
 error[E0109]: lifetime arguments are not allowed for this type
-  --> $DIR/prim-with-args.rs:24:12
+  --> $DIR/prim-with-args.rs:24:13
    |
-LL | let x: u64<'static>;
-   |            ^^^^^^^ lifetime argument not allowed
+LL | let _x: u32<'static>;
+   |             ^^^^^^^ lifetime argument not allowed
+   |
+help: primitive type `u32` doesn't have type parameters
+   |
+LL - let _x: u32<'static>;
+LL + let _x: u32;
+   | 
 
 error[E0109]: lifetime arguments are not allowed for this type
   --> $DIR/prim-with-args.rs:25:13
    |
-LL | let x: char<'static>;
+LL | let _x: u64<'static>;
    |             ^^^^^^^ lifetime argument not allowed
+   |
+help: primitive type `u64` doesn't have type parameters
+   |
+LL - let _x: u64<'static>;
+LL + let _x: u64;
+   | 
+
+error[E0109]: lifetime arguments are not allowed for this type
+  --> $DIR/prim-with-args.rs:26:14
+   |
+LL | let _x: char<'static>;
+   |              ^^^^^^^ lifetime argument not allowed
+   |
+help: primitive type `char` doesn't have type parameters
+   |
+LL - let _x: char<'static>;
+LL + let _x: char;
+   | 
 
 error: aborting due to 22 previous errors
 
diff --git a/src/test/ui/usize-generic-argument-parent.stderr b/src/test/ui/usize-generic-argument-parent.stderr
index f1eae3b5008..98505d7bbe8 100644
--- a/src/test/ui/usize-generic-argument-parent.stderr
+++ b/src/test/ui/usize-generic-argument-parent.stderr
@@ -3,6 +3,12 @@ error[E0109]: const arguments are not allowed for this type
    |
 LL |     let x: usize<foo>;
    |                  ^^^ const argument not allowed
+   |
+help: primitive type `usize` doesn't have type parameters
+   |
+LL -     let x: usize<foo>;
+LL +     let x: usize;
+   | 
 
 error: aborting due to previous error