about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-05-13 08:08:20 +0000
committerbors <bors@rust-lang.org>2021-05-13 08:08:20 +0000
commit703f2e1685a63c9718bcc3b09eb33a24334a7541 (patch)
treedfb1e19f4dee3445caeb1936022fc56eb14d0105
parent72d07257ed46c70bcaf719e15882af539d0a5155 (diff)
parent4c72efc8167405ca1cc3002266a9bf15f70dafb3 (diff)
downloadrust-703f2e1685a63c9718bcc3b09eb33a24334a7541.tar.gz
rust-703f2e1685a63c9718bcc3b09eb33a24334a7541.zip
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
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs19
-rw-r--r--src/test/ui/const-generics/diagnostics.stderr22
-rw-r--r--src/test/ui/missing/missing-items/missing-type-parameter2.rs22
-rw-r--r--src/test/ui/missing/missing-items/missing-type-parameter2.stderr121
-rw-r--r--src/test/ui/traits/issue-75627.stderr4
-rw-r--r--src/test/ui/traits/issue-78372.stderr11
6 files changed, 190 insertions, 9 deletions
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 13e457507cf..03b578d4ade 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -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] = &param.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
                         };
diff --git a/src/test/ui/const-generics/diagnostics.stderr b/src/test/ui/const-generics/diagnostics.stderr
index c8ee6ad61ec..2e3132c2eb7 100644
--- a/src/test/ui/const-generics/diagnostics.stderr
+++ b/src/test/ui/const-generics/diagnostics.stderr
@@ -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
diff --git a/src/test/ui/missing/missing-items/missing-type-parameter2.rs b/src/test/ui/missing/missing-items/missing-type-parameter2.rs
new file mode 100644
index 00000000000..15dc5ef797b
--- /dev/null
+++ b/src/test/ui/missing/missing-items/missing-type-parameter2.rs
@@ -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() {
+}
diff --git a/src/test/ui/missing/missing-items/missing-type-parameter2.stderr b/src/test/ui/missing/missing-items/missing-type-parameter2.stderr
new file mode 100644
index 00000000000..985a9bb2a3f
--- /dev/null
+++ b/src/test/ui/missing/missing-items/missing-type-parameter2.stderr
@@ -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`.
diff --git a/src/test/ui/traits/issue-75627.stderr b/src/test/ui/traits/issue-75627.stderr
index 92d9ac0f84c..432ddf2dcdb 100644
--- a/src/test/ui/traits/issue-75627.stderr
+++ b/src/test/ui/traits/issue-75627.stderr
@@ -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
 
diff --git a/src/test/ui/traits/issue-78372.stderr b/src/test/ui/traits/issue-78372.stderr
index 9267e838cea..e63740c4ea9 100644
--- a/src/test/ui/traits/issue-78372.stderr
+++ b/src/test/ui/traits/issue-78372.stderr
@@ -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