Rollup merge of #73320 - estebank:type-param-sugg-more, r=davidtwco
Make new type param suggestion more targetted Do not suggest new type param when encountering a missing type in an ADT field with generic parameters. Fix #72640.
This commit is contained in:
commit
f4b5f581a9
@ -485,6 +485,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
||||
module_path.push(Segment {
|
||||
ident: Ident { name: kw::PathRoot, span: source.ident.span },
|
||||
id: Some(self.r.next_node_id()),
|
||||
has_generic_args: false,
|
||||
});
|
||||
source.ident.name = crate_name;
|
||||
}
|
||||
|
@ -920,20 +920,47 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> {
|
||||
&self,
|
||||
path: &[Segment],
|
||||
) -> Option<(Span, &'static str, String, Applicability)> {
|
||||
let ident = match path {
|
||||
[segment] => segment.ident,
|
||||
let (ident, span) = match path {
|
||||
[segment] if !segment.has_generic_args => {
|
||||
(segment.ident.to_string(), segment.ident.span)
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
match (
|
||||
self.diagnostic_metadata.current_item,
|
||||
self.diagnostic_metadata.currently_processing_generics,
|
||||
) {
|
||||
(Some(Item { kind: ItemKind::Fn(..), ident, .. }), true) if ident.name == sym::main => {
|
||||
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 => {
|
||||
// Ignore `fn main()` as we don't want to suggest `fn main<T>()`
|
||||
}
|
||||
(Some(Item { kind, .. }), true) => {
|
||||
(
|
||||
Some(Item {
|
||||
kind:
|
||||
kind @ ItemKind::Fn(..)
|
||||
| kind @ ItemKind::Enum(..)
|
||||
| kind @ ItemKind::Struct(..)
|
||||
| kind @ ItemKind::Union(..),
|
||||
..
|
||||
}),
|
||||
true,
|
||||
)
|
||||
| (Some(Item { kind, .. }), false) => {
|
||||
// Likely missing type parameter.
|
||||
if let Some(generics) = kind.generics() {
|
||||
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;
|
||||
}
|
||||
let msg = "you might be missing a type parameter";
|
||||
let (span, sugg) = if let [.., param] = &generics.params[..] {
|
||||
let span = if let [.., bound] = ¶m.bounds[..] {
|
||||
|
@ -225,13 +225,15 @@ enum VisResolutionError<'a> {
|
||||
ModuleOnly(Span),
|
||||
}
|
||||
|
||||
// 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`.
|
||||
/// 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`.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Segment {
|
||||
ident: Ident,
|
||||
id: Option<NodeId>,
|
||||
/// Signals whether this `PathSegment` has generic arguments. Used to avoid providing
|
||||
/// nonsensical suggestions.
|
||||
has_generic_args: bool,
|
||||
}
|
||||
|
||||
impl Segment {
|
||||
@ -240,7 +242,7 @@ impl Segment {
|
||||
}
|
||||
|
||||
fn from_ident(ident: Ident) -> Segment {
|
||||
Segment { ident, id: None }
|
||||
Segment { ident, id: None, has_generic_args: false }
|
||||
}
|
||||
|
||||
fn names_to_string(segments: &[Segment]) -> String {
|
||||
@ -250,7 +252,7 @@ impl Segment {
|
||||
|
||||
impl<'a> From<&'a ast::PathSegment> for Segment {
|
||||
fn from(seg: &'a ast::PathSegment) -> Segment {
|
||||
Segment { ident: seg.ident, id: Some(seg.id) }
|
||||
Segment { ident: seg.ident, id: Some(seg.id), has_generic_args: seg.args.is_some() }
|
||||
}
|
||||
}
|
||||
|
||||
@ -2017,7 +2019,7 @@ impl<'a> Resolver<'a> {
|
||||
path, opt_ns, record_used, path_span, crate_lint,
|
||||
);
|
||||
|
||||
for (i, &Segment { ident, id }) in path.iter().enumerate() {
|
||||
for (i, &Segment { ident, id, has_generic_args: _ }) in path.iter().enumerate() {
|
||||
debug!("resolve_path ident {} {:?} {:?}", i, ident, id);
|
||||
let record_segment_res = |this: &mut Self, res| {
|
||||
if record_used {
|
||||
|
@ -4,7 +4,16 @@ error[E0412]: cannot find type `A` in this scope
|
||||
LL | fn foo2<I: Foo>(x: I) {
|
||||
| - similarly named type parameter `I` defined here
|
||||
LL | let _: A = x.boo();
|
||||
| ^ help: a type parameter with a similar name exists: `I`
|
||||
| ^
|
||||
|
|
||||
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) {
|
||||
| ^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
9
src/test/ui/suggestions/type-not-found-in-adt-field.rs
Normal file
9
src/test/ui/suggestions/type-not-found-in-adt-field.rs
Normal file
@ -0,0 +1,9 @@
|
||||
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() {}
|
17
src/test/ui/suggestions/type-not-found-in-adt-field.stderr
Normal file
17
src/test/ui/suggestions/type-not-found-in-adt-field.stderr
Normal file
@ -0,0 +1,17 @@
|
||||
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`.
|
Loading…
x
Reference in New Issue
Block a user