Auto merge of #85041 - mibac138:suggest-generics, r=estebank
Suggest adding a type parameter for impls Add a new suggestion upon encountering an unknown type in a `impl` that suggests adding a new type parameter. This diagnostic suggests to add a new type parameter even though it may be a const parameter, however after adding the parameter and running rustc again a follow up error steers the user to change the type parameter to a const parameter. ```rust struct X<const C: ()>(); impl X<C> {} ``` suggests ``` error[E0412]: cannot find type `C` in this scope --> bar.rs:2:8 | 1 | struct X<const C: ()>(); | ------------------------ similarly named struct `X` defined here 2 | impl X<C> {} | ^ | help: a struct with a similar name exists | 2 | impl X<X> {} | ^ help: you might be missing a type parameter | 2 | impl<C> X<C> {} | ^^^ ``` After adding a type parameter the code now becomes ```rust struct X<const C: ()>(); impl<C> X<C> {} ``` and the error now fully steers the user towards the correct code ``` error[E0747]: type provided when a constant was expected --> bar.rs:2:11 | 2 | impl<C> X<C> {} | ^ | help: consider changing this type parameter to be a `const` generic | 2 | impl<const C: ()> X<C> {} | ^^^^^^^^^^^ ``` r? `@estebank` Somewhat related #84946
This commit is contained in:
commit
703f2e1685
6 changed files with 190 additions and 9 deletions
|
@ -6,7 +6,10 @@ use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot};
|
|||
use crate::{PathResult, PathSource, Segment};
|
||||
|
||||
use rustc_ast::visit::FnKind;
|
||||
use rustc_ast::{self as ast, Expr, ExprKind, Item, ItemKind, NodeId, Path, Ty, TyKind};
|
||||
use rustc_ast::{
|
||||
self as ast, Expr, ExprKind, GenericParam, GenericParamKind, Item, ItemKind, NodeId, Path, Ty,
|
||||
TyKind,
|
||||
};
|
||||
use rustc_ast_pretty::pprust::path_segment_to_string;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, SuggestionStyle};
|
||||
|
@ -1600,8 +1603,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
|||
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 => {
|
||||
match (self.diagnostic_metadata.current_item, single_uppercase_char, self.diagnostic_metadata.currently_processing_generics) {
|
||||
(Some(Item { kind: ItemKind::Fn(..), ident, .. }), _, _) if ident.name == sym::main => {
|
||||
// Ignore `fn main()` as we don't want to suggest `fn main<T>()`
|
||||
}
|
||||
(
|
||||
|
@ -1613,9 +1616,11 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
|||
| kind @ ItemKind::Union(..),
|
||||
..
|
||||
}),
|
||||
true,
|
||||
true, _
|
||||
)
|
||||
| (Some(Item { kind, .. }), false) => {
|
||||
// Without the 2nd `true`, we'd suggest `impl <T>` for `impl T` when a type `T` isn't found
|
||||
| (Some(Item { kind: kind @ ItemKind::Impl(..), .. }), true, true)
|
||||
| (Some(Item { kind, .. }), false, _) => {
|
||||
// Likely missing type parameter.
|
||||
if let Some(generics) = kind.generics() {
|
||||
if span.overlaps(generics.span) {
|
||||
|
@ -1633,6 +1638,10 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
|||
let (span, sugg) = if let [.., param] = &generics.params[..] {
|
||||
let span = if let [.., bound] = ¶m.bounds[..] {
|
||||
bound.span()
|
||||
} else if let GenericParam {
|
||||
kind: GenericParamKind::Const { ty, kw_span: _, default }, ..
|
||||
} = param {
|
||||
default.as_ref().map(|def| def.value.span).unwrap_or(ty.span)
|
||||
} else {
|
||||
param.ident.span
|
||||
};
|
||||
|
|
|
@ -5,7 +5,16 @@ LL | struct A<const N: u8>;
|
|||
| ---------------------- similarly named struct `A` defined here
|
||||
LL | trait Foo {}
|
||||
LL | impl Foo for A<N> {}
|
||||
| ^ help: a struct with a similar name exists: `A`
|
||||
| ^
|
||||
|
|
||||
help: a struct with a similar name exists
|
||||
|
|
||||
LL | impl Foo for A<A> {}
|
||||
| ^
|
||||
help: you might be missing a type parameter
|
||||
|
|
||||
LL | impl<N> Foo for A<N> {}
|
||||
| ^^^
|
||||
|
||||
error[E0412]: cannot find type `T` in this scope
|
||||
--> $DIR/diagnostics.rs:16:32
|
||||
|
@ -14,7 +23,16 @@ LL | struct A<const N: u8>;
|
|||
| ---------------------- similarly named struct `A` defined here
|
||||
...
|
||||
LL | impl<const N: u8> Foo for C<N, T> {}
|
||||
| ^ help: a struct with a similar name exists: `A`
|
||||
| ^
|
||||
|
|
||||
help: a struct with a similar name exists
|
||||
|
|
||||
LL | impl<const N: u8> Foo for C<N, A> {}
|
||||
| ^
|
||||
help: you might be missing a type parameter
|
||||
|
|
||||
LL | impl<const N: u8, T> Foo for C<N, T> {}
|
||||
| ^^^
|
||||
|
||||
error[E0747]: unresolved item provided when a constant was expected
|
||||
--> $DIR/diagnostics.rs:7:16
|
||||
|
|
22
src/test/ui/missing/missing-items/missing-type-parameter2.rs
Normal file
22
src/test/ui/missing/missing-items/missing-type-parameter2.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
#![allow(incomplete_features)]
|
||||
#![feature(const_generics_defaults)]
|
||||
|
||||
struct X<const N: u8>();
|
||||
|
||||
impl X<N> {}
|
||||
//~^ ERROR cannot find type `N` in this scope
|
||||
//~| ERROR unresolved item provided when a constant was expected
|
||||
impl<T, const A: u8 = 2> X<N> {}
|
||||
//~^ ERROR cannot find type `N` in this scope
|
||||
//~| ERROR defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
|
||||
//~| ERROR unresolved item provided when a constant was expected
|
||||
|
||||
fn foo(_: T) where T: Send {}
|
||||
//~^ ERROR cannot find type `T` in this scope
|
||||
//~| ERROR cannot find type `T` in this scope
|
||||
|
||||
fn bar<const N: u8>(_: A) {}
|
||||
//~^ ERROR cannot find type `A` in this scope
|
||||
|
||||
fn main() {
|
||||
}
|
121
src/test/ui/missing/missing-items/missing-type-parameter2.stderr
Normal file
121
src/test/ui/missing/missing-items/missing-type-parameter2.stderr
Normal file
|
@ -0,0 +1,121 @@
|
|||
error[E0412]: cannot find type `N` in this scope
|
||||
--> $DIR/missing-type-parameter2.rs:6:8
|
||||
|
|
||||
LL | struct X<const N: u8>();
|
||||
| ------------------------ similarly named struct `X` defined here
|
||||
LL |
|
||||
LL | impl X<N> {}
|
||||
| ^
|
||||
|
|
||||
help: a struct with a similar name exists
|
||||
|
|
||||
LL | impl X<X> {}
|
||||
| ^
|
||||
help: you might be missing a type parameter
|
||||
|
|
||||
LL | impl<N> X<N> {}
|
||||
| ^^^
|
||||
|
||||
error[E0412]: cannot find type `N` in this scope
|
||||
--> $DIR/missing-type-parameter2.rs:9:28
|
||||
|
|
||||
LL | impl<T, const A: u8 = 2> X<N> {}
|
||||
| - ^
|
||||
| |
|
||||
| similarly named type parameter `T` defined here
|
||||
|
|
||||
help: a type parameter with a similar name exists
|
||||
|
|
||||
LL | impl<T, const A: u8 = 2> X<T> {}
|
||||
| ^
|
||||
help: you might be missing a type parameter
|
||||
|
|
||||
LL | impl<T, const A: u8 = 2, N> X<N> {}
|
||||
| ^^^
|
||||
|
||||
error[E0412]: cannot find type `T` in this scope
|
||||
--> $DIR/missing-type-parameter2.rs:14:20
|
||||
|
|
||||
LL | struct X<const N: u8>();
|
||||
| ------------------------ similarly named struct `X` defined here
|
||||
...
|
||||
LL | fn foo(_: T) where T: Send {}
|
||||
| ^
|
||||
|
|
||||
help: a struct with a similar name exists
|
||||
|
|
||||
LL | fn foo(_: T) where X: Send {}
|
||||
| ^
|
||||
help: you might be missing a type parameter
|
||||
|
|
||||
LL | fn foo<T>(_: T) where T: Send {}
|
||||
| ^^^
|
||||
|
||||
error[E0412]: cannot find type `T` in this scope
|
||||
--> $DIR/missing-type-parameter2.rs:14:11
|
||||
|
|
||||
LL | struct X<const N: u8>();
|
||||
| ------------------------ similarly named struct `X` defined here
|
||||
...
|
||||
LL | fn foo(_: T) where T: Send {}
|
||||
| ^
|
||||
|
|
||||
help: a struct with a similar name exists
|
||||
|
|
||||
LL | fn foo(_: X) where T: Send {}
|
||||
| ^
|
||||
help: you might be missing a type parameter
|
||||
|
|
||||
LL | fn foo<T>(_: T) where T: Send {}
|
||||
| ^^^
|
||||
|
||||
error[E0412]: cannot find type `A` in this scope
|
||||
--> $DIR/missing-type-parameter2.rs:18:24
|
||||
|
|
||||
LL | struct X<const N: u8>();
|
||||
| ------------------------ similarly named struct `X` defined here
|
||||
...
|
||||
LL | fn bar<const N: u8>(_: A) {}
|
||||
| ^
|
||||
|
|
||||
help: a struct with a similar name exists
|
||||
|
|
||||
LL | fn bar<const N: u8>(_: X) {}
|
||||
| ^
|
||||
help: you might be missing a type parameter
|
||||
|
|
||||
LL | fn bar<const N: u8, A>(_: A) {}
|
||||
| ^^^
|
||||
|
||||
error[E0747]: unresolved item provided when a constant was expected
|
||||
--> $DIR/missing-type-parameter2.rs:6:8
|
||||
|
|
||||
LL | impl X<N> {}
|
||||
| ^
|
||||
|
|
||||
help: if this generic argument was intended as a const parameter, surround it with braces
|
||||
|
|
||||
LL | impl X<{ N }> {}
|
||||
| ^ ^
|
||||
|
||||
error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
|
||||
--> $DIR/missing-type-parameter2.rs:9:15
|
||||
|
|
||||
LL | impl<T, const A: u8 = 2> X<N> {}
|
||||
| ^
|
||||
|
||||
error[E0747]: unresolved item provided when a constant was expected
|
||||
--> $DIR/missing-type-parameter2.rs:9:28
|
||||
|
|
||||
LL | impl<T, const A: u8 = 2> X<N> {}
|
||||
| ^
|
||||
|
|
||||
help: if this generic argument was intended as a const parameter, surround it with braces
|
||||
|
|
||||
LL | impl<T, const A: u8 = 2> X<{ N }> {}
|
||||
| ^ ^
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0412, E0747.
|
||||
For more information about an error, try `rustc --explain E0412`.
|
|
@ -2,7 +2,9 @@ error[E0412]: cannot find type `T` in this scope
|
|||
--> $DIR/issue-75627.rs:3:26
|
||||
|
|
||||
LL | unsafe impl Send for Foo<T> {}
|
||||
| ^ not found in this scope
|
||||
| - ^ not found in this scope
|
||||
| |
|
||||
| help: you might be missing a type parameter: `<T>`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -13,9 +13,18 @@ error[E0412]: cannot find type `U` in this scope
|
|||
--> $DIR/issue-78372.rs:3:31
|
||||
|
|
||||
LL | impl<T> DispatchFromDyn<Smaht<U, MISC>> for T {}
|
||||
| - ^ help: a type parameter with a similar name exists: `T`
|
||||
| - ^
|
||||
| |
|
||||
| similarly named type parameter `T` defined here
|
||||
|
|
||||
help: a type parameter with a similar name exists
|
||||
|
|
||||
LL | impl<T> DispatchFromDyn<Smaht<T, MISC>> for T {}
|
||||
| ^
|
||||
help: you might be missing a type parameter
|
||||
|
|
||||
LL | impl<T, U> DispatchFromDyn<Smaht<U, MISC>> for T {}
|
||||
| ^^^
|
||||
|
||||
error[E0412]: cannot find type `MISC` in this scope
|
||||
--> $DIR/issue-78372.rs:3:34
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue