Change:
Rustc should know that is not in the right direction because that still wouldn't make a valid thing to write; type parameters can't have type parameters (yet??). Separately, should also have prevented the suggestion in this case, but is an independent issue. cc who worked on this recently in .

Discussion:
module_path.push(Segment { ident: Ident { name: kw::PathRoot, span: source.ident.span }, id: Some(self.r.next_node_id()), <ins> has_generic_args: false, </ins> }); source.ident.name = crate_name; }

&self, path: &[Segment], ) -> Option<(Span, &'static str, String, Applicability)> { <del> let ident = match path { [segment] => segment.ident, </del> <ins> let (ident, span) = match path { [segment] if !segment.has_generic_args => { (segment.ident.to_string(), segment.ident.span) } </ins> _ => return None, }; <del> match ( self.diagnostic_metadata.current_item, self.diagnostic_metadata.currently_processing_generics, ) { (Some(Item { kind: ItemKind::Fn(..), ident, .. }), true) if ident.name == sym::main => { </del> <ins> let mut iter = ident.chars().map(|c| c.is_uppercase()); let single_uppercase_char = matches!(iter.next(), Some(true)) && matches!(iter.next(), None); if !self.diagnostic_metadata.currently_processing_generics && !single_uppercase_char { return None; } match (self.diagnostic_metadata.current_item, single_uppercase_char) { (Some(Item { kind: ItemKind::Fn(..), ident, .. }), _) if ident.name == sym::main => { </ins> // Ignore `fn main()` as we don't want to suggest `fn main<T>()` } <del> (Some(Item { kind, .. }), true) => { </del> <ins> ( Some(Item { kind: kind @ ItemKind::Fn(..) | kind @ ItemKind::Enum(..) | kind @ ItemKind::Struct(..) | kind @ ItemKind::Union(..), .. }), true, ) | (Some(Item { kind, .. }), false) => { </ins> // Likely missing type parameter. if let Some(generics) = kind.generics() { <ins> if span.overlaps(generics.span) { // Avoid the following: // error[E0405]: cannot find trait `A` in this scope //  --> $DIR/typo-suggestion-named-underscore.rs:CC:LL //   | // L | fn foo<T: A>(x: T) {} // Shouldn't suggest underscore //   |           ^- help: you might be missing a type parameter: `, A` //   |           | //   |           not found in this scope return None; } </ins> let msg = "you might be missing a type parameter"; let (span, sugg) = if let [.., param] = &generics.params[..] { let span = if let [.., bound] = &param.bounds[..] {

ModuleOnly(Span), } <del> // A minimal representation of a path segment. We use this in resolve because // we synthesize 'path segments' which don't have the rest of an AST or HIR // `PathSegment`. </del> <ins> /// A minimal representation of a path segment. We use this in resolve because we synthesize 'path /// segments' which don't have the rest of an AST or HIR `PathSegment`. </ins> #[derive(Clone, Copy, Debug)] pub struct Segment { ident: Ident, id: Option<NodeId>, <ins> /// Signals whether this `PathSegment` has generic arguments. Used to avoid providing /// nonsensical suggestions. has_generic_args: bool, </ins> } impl Segment {

} fn from_ident(ident: Ident) -> Segment { <del> Segment { ident, id: None } </del> <ins> Segment { ident, id: None, has_generic_args: false } </ins> } fn names_to_string(segments: &[Segment]) -> String {

impl<'a> From<&'a ast::PathSegment> for Segment { fn from(seg: &'a ast::PathSegment) -> Segment { <del> Segment { ident: seg.ident, id: Some(seg.id) } </del> <ins> Segment { ident: seg.ident, id: Some(seg.id), has_generic_args: seg.args.is_some() } </ins> } }

path, opt_ns, record_used, path_span, crate_lint, ); <del> for (i, &Segment { ident, id }) in path.iter().enumerate() { </del> <ins> for (i, &Segment { ident, id, has_generic_args: _ }) in path.iter().enumerate() { </ins> debug!("resolve_path ident {} {:?} {:?}", i, ident, id); let record_segment_res = |this: &mut Self, res| { if record_used {

LL | fn foo2<I: Foo>(x: I) { |         - similarly named type parameter `I` defined here LL |     let _: A = x.boo(); <del> |            ^ help: a type parameter with a similar name exists: `I` </del> <ins> |            ^ | help: a type parameter with a similar name exists | LL |     let _: I = x.boo(); |            ^ help: you might be missing a type parameter | LL | fn foo2<I: Foo, A>(x: I) { |               ^^^ </ins> error: aborting due to previous error

<ins> struct Struct { m: Vec<Someunknownname<String, ()>>, //~ ERROR cannot find type `Someunknownname` in this scope //~^ NOTE not found in this scope } struct OtherStruct { //~ HELP you might be missing a type parameter m: K, //~ ERROR cannot find type `K` in this scope //~^ NOTE not found in this scope } fn main() {} </ins>

<ins> error[E0412]: cannot find type `Someunknownname` in this scope --> $DIR/type-not-found-in-adt-field.rs:2:12 | LL |     m: Vec<Someunknownname<String, ()>>, |            ^^^^^^^^^^^^^^^ not found in this scope error[E0412]: cannot find type `K` in this scope --> $DIR/type-not-found-in-adt-field.rs:6:8 | LL | struct OtherStruct { |                   - help: you might be missing a type parameter: `<K>` LL |     m: K, |        ^ not found in this scope error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0412`. </ins>