From be1ed00712ce0b884e1fc9779f25b1758e994d0b Mon Sep 17 00:00:00 2001
From: kadmin <julianknodt@gmail.com>
Date: Sat, 13 Feb 2021 07:53:28 +0000
Subject: [PATCH 1/3] Add additional type info to mismatch err

---
 compiler/rustc_typeck/src/astconv/generics.rs | 51 ++++++++++++++-----
 src/test/ui/const-generics/diagnostics.rs     | 13 +++++
 src/test/ui/const-generics/diagnostics.stderr | 27 ++++++++++
 .../ui/const-generics/invalid-enum.stderr     | 20 --------
 4 files changed, 79 insertions(+), 32 deletions(-)
 create mode 100644 src/test/ui/const-generics/diagnostics.rs
 create mode 100644 src/test/ui/const-generics/diagnostics.stderr

diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index 67e37ca8d8e49..341f6fadba174 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -24,6 +24,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         tcx: TyCtxt<'_>,
         arg: &GenericArg<'_>,
         param: &GenericParamDef,
+        // DefId of the function
+        //body_def_id: DefId,
         possible_ordering_error: bool,
         help: Option<&str>,
     ) {
@@ -46,19 +48,44 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         // Specific suggestion set for diagnostics
         match (arg, &param.kind) {
             (
-                GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. }),
-                GenericParamDefKind::Const { .. },
+                GenericArg::Type(hir::Ty {
+                    kind: hir::TyKind::Path(rustc_hir::QPath::Resolved(_, path)),
+                    ..
+                }),
+                GenericParamDefKind::Const,
             ) => {
-                let suggestions = vec![
-                    (arg.span().shrink_to_lo(), String::from("{ ")),
-                    (arg.span().shrink_to_hi(), String::from(" }")),
-                ];
-                err.multipart_suggestion(
-                    "if this generic argument was intended as a const parameter, \
-                try surrounding it with braces:",
-                    suggestions,
-                    Applicability::MaybeIncorrect,
-                );
+                use rustc_hir::def::{DefKind, Res};
+                match path.res {
+                    Res::Err => {}
+                    Res::Def(DefKind::TyParam, src_def_id) => (|| {
+                        let param_hir_id = match param.def_id.as_local() {
+                            Some(x) => tcx.hir().local_def_id_to_hir_id(x),
+                            None => return,
+                        };
+                        let param_name = tcx.hir().ty_param_name(param_hir_id);
+                        let param_type = tcx.type_of(param.def_id);
+                        if param_type.is_suggestable() {
+                            err.span_suggestion(
+                                tcx.def_span(src_def_id),
+                                &format!("try changing to a const-generic parameter:"),
+                                format!("const {}: {}", param_name, param_type),
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+                    })(),
+                    _ => {
+                        let suggestions = vec![
+                            (arg.span().shrink_to_lo(), String::from("{ ")),
+                            (arg.span().shrink_to_hi(), String::from(" }")),
+                        ];
+                        err.multipart_suggestion(
+                            "if this generic argument was intended as a const parameter, \
+                  try surrounding it with braces:",
+                            suggestions,
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                }
             }
             (
                 GenericArg::Type(hir::Ty { kind: hir::TyKind::Array(_, len), .. }),
diff --git a/src/test/ui/const-generics/diagnostics.rs b/src/test/ui/const-generics/diagnostics.rs
new file mode 100644
index 0000000000000..c90e3d0e0eba9
--- /dev/null
+++ b/src/test/ui/const-generics/diagnostics.rs
@@ -0,0 +1,13 @@
+#![crate_type="lib"]
+#![feature(const_generics)]
+#![allow(incomplete_features)]
+
+struct A<const N: u8>;
+trait Foo {}
+impl Foo for A<N> {}
+//~^ ERROR type provided when a constant
+//~| ERROR cannot find type
+
+struct B<const N: u8>;
+impl<N> Foo for B<N> {}
+//~^ ERROR type provided when a constant
diff --git a/src/test/ui/const-generics/diagnostics.stderr b/src/test/ui/const-generics/diagnostics.stderr
new file mode 100644
index 0000000000000..a66858a310c85
--- /dev/null
+++ b/src/test/ui/const-generics/diagnostics.stderr
@@ -0,0 +1,27 @@
+error[E0412]: cannot find type `N` in this scope
+  --> $DIR/diagnostics.rs:7: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`
+
+error[E0747]: type provided when a constant was expected
+  --> $DIR/diagnostics.rs:7:16
+   |
+LL | impl Foo for A<N> {}
+   |                ^
+
+error[E0747]: type provided when a constant was expected
+  --> $DIR/diagnostics.rs:12:19
+   |
+LL | impl<N> Foo for B<N> {}
+   |      -            ^
+   |      |
+   |      help: try changing to a const-generic parameter:: `const N: u8`
+
+error: aborting due to 3 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/const-generics/invalid-enum.stderr b/src/test/ui/const-generics/invalid-enum.stderr
index 7822fc072e35c..c062fc9ac88b3 100644
--- a/src/test/ui/const-generics/invalid-enum.stderr
+++ b/src/test/ui/const-generics/invalid-enum.stderr
@@ -30,44 +30,24 @@ error[E0747]: type provided when a constant was expected
    |
 LL |   let _: Example<CompileFlag::A, _> = Example { x: 0 };
    |                  ^^^^^^^^^^^^^^
-   |
-help: if this generic argument was intended as a const parameter, try surrounding it with braces:
-   |
-LL |   let _: Example<{ CompileFlag::A }, _> = Example { x: 0 };
-   |                  ^                ^
 
 error[E0747]: type provided when a constant was expected
   --> $DIR/invalid-enum.rs:33:18
    |
 LL |   let _: Example<Example::ASSOC_FLAG, _> = Example { x: 0 };
    |                  ^^^^^^^^^^^^^^^^^^^
-   |
-help: if this generic argument was intended as a const parameter, try surrounding it with braces:
-   |
-LL |   let _: Example<{ Example::ASSOC_FLAG }, _> = Example { x: 0 };
-   |                  ^                     ^
 
 error[E0747]: type provided when a constant was expected
   --> $DIR/invalid-enum.rs:21:12
    |
 LL |   test_1::<CompileFlag::A>();
    |            ^^^^^^^^^^^^^^
-   |
-help: if this generic argument was intended as a const parameter, try surrounding it with braces:
-   |
-LL |   test_1::<{ CompileFlag::A }>();
-   |            ^                ^
 
 error[E0747]: type provided when a constant was expected
   --> $DIR/invalid-enum.rs:25:15
    |
 LL |   test_2::<_, CompileFlag::A>(0);
    |               ^^^^^^^^^^^^^^
-   |
-help: if this generic argument was intended as a const parameter, try surrounding it with braces:
-   |
-LL |   test_2::<_, { CompileFlag::A }>(0);
-   |               ^                ^
 
 error: aborting due to 7 previous errors
 

From b97951b50f81862ccd997d48b20f50d05cd5157e Mon Sep 17 00:00:00 2001
From: kadmin <julianknodt@gmail.com>
Date: Sun, 14 Feb 2021 04:35:18 +0000
Subject: [PATCH 2/3] Update w/ comments

---
 compiler/rustc_typeck/src/astconv/generics.rs | 60 ++++++++++---------
 .../const-param-shadowing.stderr              |  2 +-
 src/test/ui/const-generics/diagnostics.rs     | 11 +++-
 src/test/ui/const-generics/diagnostics.stderr | 33 +++++++++-
 src/test/ui/const-generics/invalid-enum.rs    | 12 ++--
 .../ui/const-generics/invalid-enum.stderr     | 26 +++++++-
 6 files changed, 101 insertions(+), 43 deletions(-)

diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index 341f6fadba174..b421adbf9eab1 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -6,8 +6,9 @@ use crate::astconv::{
 use crate::errors::AssocTypeBindingNotAllowed;
 use crate::structured_errors::{StructuredDiagnostic, WrongNumberOfGenericArgs};
 use rustc_ast::ast::ParamKindOrd;
-use rustc_errors::{struct_span_err, Applicability, ErrorReported};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
 use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::GenericArg;
 use rustc_middle::ty::{
@@ -24,8 +25,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         tcx: TyCtxt<'_>,
         arg: &GenericArg<'_>,
         param: &GenericParamDef,
-        // DefId of the function
-        //body_def_id: DefId,
         possible_ordering_error: bool,
         help: Option<&str>,
     ) {
@@ -45,6 +44,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
         }
 
+        let add_braces_suggestion = |arg: &GenericArg<'_>, err: &mut DiagnosticBuilder<'_>| {
+            let suggestions = vec![
+                (arg.span().shrink_to_lo(), String::from("{ ")),
+                (arg.span().shrink_to_hi(), String::from(" }")),
+            ];
+            err.multipart_suggestion(
+                "if this generic argument was intended as a const parameter, \
+                 surround it with braces",
+                suggestions,
+                Applicability::MaybeIncorrect,
+            );
+        };
+
         // Specific suggestion set for diagnostics
         match (arg, &param.kind) {
             (
@@ -53,40 +65,34 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     ..
                 }),
                 GenericParamDefKind::Const,
-            ) => {
-                use rustc_hir::def::{DefKind, Res};
-                match path.res {
-                    Res::Err => {}
-                    Res::Def(DefKind::TyParam, src_def_id) => (|| {
-                        let param_hir_id = match param.def_id.as_local() {
-                            Some(x) => tcx.hir().local_def_id_to_hir_id(x),
-                            None => return,
-                        };
+            ) => match path.res {
+                Res::Err => {
+                    add_braces_suggestion(arg, &mut err);
+                    err.set_primary_message(
+                        "unresolved item provided when a constant was expected",
+                    );
+                }
+                Res::Def(DefKind::TyParam, src_def_id) => {
+                    if let Some(param_local_id) = param.def_id.as_local() {
+                        let param_hir_id = tcx.hir().local_def_id_to_hir_id(param_local_id);
                         let param_name = tcx.hir().ty_param_name(param_hir_id);
                         let param_type = tcx.type_of(param.def_id);
                         if param_type.is_suggestable() {
                             err.span_suggestion(
                                 tcx.def_span(src_def_id),
-                                &format!("try changing to a const-generic parameter:"),
+                                "consider changing this type paramater to a `const`-generic",
                                 format!("const {}: {}", param_name, param_type),
                                 Applicability::MaybeIncorrect,
                             );
-                        }
-                    })(),
-                    _ => {
-                        let suggestions = vec![
-                            (arg.span().shrink_to_lo(), String::from("{ ")),
-                            (arg.span().shrink_to_hi(), String::from(" }")),
-                        ];
-                        err.multipart_suggestion(
-                            "if this generic argument was intended as a const parameter, \
-                  try surrounding it with braces:",
-                            suggestions,
-                            Applicability::MaybeIncorrect,
-                        );
+                        };
                     }
                 }
-            }
+                _ => add_braces_suggestion(arg, &mut err),
+            },
+            (
+                GenericArg::Type(hir::Ty { kind: hir::TyKind::Path(_), .. }),
+                GenericParamDefKind::Const,
+            ) => add_braces_suggestion(arg, &mut err),
             (
                 GenericArg::Type(hir::Ty { kind: hir::TyKind::Array(_, len), .. }),
                 GenericParamDefKind::Const { .. },
diff --git a/src/test/ui/const-generics/const-param-shadowing.stderr b/src/test/ui/const-generics/const-param-shadowing.stderr
index 7447ca3ff3631..17ccd2f3527b0 100644
--- a/src/test/ui/const-generics/const-param-shadowing.stderr
+++ b/src/test/ui/const-generics/const-param-shadowing.stderr
@@ -4,7 +4,7 @@ error[E0747]: type provided when a constant was expected
 LL | fn test<const N: usize>() -> Foo<N> {
    |                                  ^
    |
-help: if this generic argument was intended as a const parameter, try surrounding it with braces:
+help: if this generic argument was intended as a const parameter, surround it with braces
    |
 LL | fn test<const N: usize>() -> Foo<{ N }> {
    |                                  ^   ^
diff --git a/src/test/ui/const-generics/diagnostics.rs b/src/test/ui/const-generics/diagnostics.rs
index c90e3d0e0eba9..1581af5ab2751 100644
--- a/src/test/ui/const-generics/diagnostics.rs
+++ b/src/test/ui/const-generics/diagnostics.rs
@@ -1,13 +1,18 @@
 #![crate_type="lib"]
-#![feature(const_generics)]
+#![feature(min_const_generics)]
 #![allow(incomplete_features)]
 
 struct A<const N: u8>;
 trait Foo {}
 impl Foo for A<N> {}
-//~^ ERROR type provided when a constant
-//~| ERROR cannot find type
+//~^ ERROR cannot find type
+//~| unresolved item provided when a constant
 
 struct B<const N: u8>;
 impl<N> Foo for B<N> {}
 //~^ ERROR type provided when a constant
+
+struct C<const C: u8, const N: u8>;
+impl<const N: u8> Foo for C<N, T> {}
+//~^ ERROR cannot find type
+//~| unresolved item provided when a constant
diff --git a/src/test/ui/const-generics/diagnostics.stderr b/src/test/ui/const-generics/diagnostics.stderr
index a66858a310c85..33f5337eb8072 100644
--- a/src/test/ui/const-generics/diagnostics.stderr
+++ b/src/test/ui/const-generics/diagnostics.stderr
@@ -7,11 +7,25 @@ LL | trait Foo {}
 LL | impl Foo for A<N> {}
    |                ^ help: a struct with a similar name exists: `A`
 
-error[E0747]: type provided when a constant was expected
+error[E0412]: cannot find type `T` in this scope
+  --> $DIR/diagnostics.rs:16:32
+   |
+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`
+
+error[E0747]: unresolved item provided when a constant was expected
   --> $DIR/diagnostics.rs:7:16
    |
 LL | impl Foo for A<N> {}
    |                ^
+   |
+help: if this generic argument was intended as a const parameter, surround it with braces
+   |
+LL | impl Foo for A<{ N }> {}
+   |                ^   ^
 
 error[E0747]: type provided when a constant was expected
   --> $DIR/diagnostics.rs:12:19
@@ -19,9 +33,22 @@ error[E0747]: type provided when a constant was expected
 LL | impl<N> Foo for B<N> {}
    |      -            ^
    |      |
-   |      help: try changing to a const-generic parameter:: `const N: u8`
+   |      help: consider changing this type paramater to a `const`-generic: `const N: u8`
+
+error[E0747]: unresolved item provided when a constant was expected
+  --> $DIR/diagnostics.rs:16:32
+   |
+LL | impl<const N: u8> Foo for C<N, T> {}
+   |                                ^
+   |
+   = note: type arguments must be provided before constant arguments
+   = help: reorder the arguments: consts: `<C, N>`
+help: if this generic argument was intended as a const parameter, surround it with braces
+   |
+LL | impl<const N: u8> Foo for C<N, { T }> {}
+   |                                ^   ^
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 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/const-generics/invalid-enum.rs b/src/test/ui/const-generics/invalid-enum.rs
index 4ca10ed8b71a2..32939dcd2861b 100644
--- a/src/test/ui/const-generics/invalid-enum.rs
+++ b/src/test/ui/const-generics/invalid-enum.rs
@@ -3,14 +3,14 @@
 
 #[derive(PartialEq, Eq)]
 enum CompileFlag {
-  A,
-  B,
+    A,
+    B,
 }
 
 pub fn test_1<const CF: CompileFlag>() {}
 pub fn test_2<T, const CF: CompileFlag>(x: T) {}
 pub struct Example<const CF: CompileFlag, T=u32>{
-  x: T,
+    x: T,
 }
 
 impl<const CF: CompileFlag, T> Example<CF, T> {
@@ -20,15 +20,15 @@ impl<const CF: CompileFlag, T> Example<CF, T> {
 pub fn main() {
   test_1::<CompileFlag::A>();
   //~^ ERROR: expected type, found variant
-  //~| ERROR: type provided when a constant was expected
+  //~| ERROR: unresolved item provided when a constant was expected
 
   test_2::<_, CompileFlag::A>(0);
   //~^ ERROR: expected type, found variant
-  //~| ERROR: type provided when a constant was expected
+  //~| ERROR: unresolved item provided when a constant was expected
 
   let _: Example<CompileFlag::A, _> = Example { x: 0 };
   //~^ ERROR: expected type, found variant
-  //~| ERROR: type provided when a constant was expected
+  //~| ERROR: unresolved item provided when a constant was expected
 
   let _: Example<Example::ASSOC_FLAG, _> = Example { x: 0 };
   //~^ ERROR: type provided when a constant was expected
diff --git a/src/test/ui/const-generics/invalid-enum.stderr b/src/test/ui/const-generics/invalid-enum.stderr
index c062fc9ac88b3..cfbc61f02543b 100644
--- a/src/test/ui/const-generics/invalid-enum.stderr
+++ b/src/test/ui/const-generics/invalid-enum.stderr
@@ -25,29 +25,49 @@ LL |   let _: Example<CompileFlag::A, _> = Example { x: 0 };
    |                  not a type
    |                  help: try using the variant's enum: `CompileFlag`
 
-error[E0747]: type provided when a constant was expected
+error[E0747]: unresolved item provided when a constant was expected
   --> $DIR/invalid-enum.rs:29:18
    |
 LL |   let _: Example<CompileFlag::A, _> = Example { x: 0 };
    |                  ^^^^^^^^^^^^^^
+   |
+help: if this generic argument was intended as a const parameter, surround it with braces
+   |
+LL |   let _: Example<{ CompileFlag::A }, _> = Example { x: 0 };
+   |                  ^                ^
 
 error[E0747]: type provided when a constant was expected
   --> $DIR/invalid-enum.rs:33:18
    |
 LL |   let _: Example<Example::ASSOC_FLAG, _> = Example { x: 0 };
    |                  ^^^^^^^^^^^^^^^^^^^
+   |
+help: if this generic argument was intended as a const parameter, surround it with braces
+   |
+LL |   let _: Example<{ Example::ASSOC_FLAG }, _> = Example { x: 0 };
+   |                  ^                     ^
 
-error[E0747]: type provided when a constant was expected
+error[E0747]: unresolved item provided when a constant was expected
   --> $DIR/invalid-enum.rs:21:12
    |
 LL |   test_1::<CompileFlag::A>();
    |            ^^^^^^^^^^^^^^
+   |
+help: if this generic argument was intended as a const parameter, surround it with braces
+   |
+LL |   test_1::<{ CompileFlag::A }>();
+   |            ^                ^
 
-error[E0747]: type provided when a constant was expected
+error[E0747]: unresolved item provided when a constant was expected
   --> $DIR/invalid-enum.rs:25:15
    |
 LL |   test_2::<_, CompileFlag::A>(0);
    |               ^^^^^^^^^^^^^^
+   |
+help: if this generic argument was intended as a const parameter, surround it with braces
+   |
+LL |   test_2::<_, { CompileFlag::A }>(0);
+   |               ^                ^
 
 error: aborting due to 7 previous errors
 

From f52029553fa97153eb7f3fc724523cc1a61dfaba Mon Sep 17 00:00:00 2001
From: kadmin <julianknodt@gmail.com>
Date: Tue, 16 Feb 2021 19:03:22 +0000
Subject: [PATCH 3/3] Remove ordering hint

---
 compiler/rustc_typeck/src/astconv/generics.rs | 4 +++-
 src/test/ui/const-generics/diagnostics.stderr | 2 --
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index b421adbf9eab1..0ea0ccaceabd4 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -70,7 +70,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     add_braces_suggestion(arg, &mut err);
                     err.set_primary_message(
                         "unresolved item provided when a constant was expected",
-                    );
+                    )
+                    .emit();
+                    return;
                 }
                 Res::Def(DefKind::TyParam, src_def_id) => {
                     if let Some(param_local_id) = param.def_id.as_local() {
diff --git a/src/test/ui/const-generics/diagnostics.stderr b/src/test/ui/const-generics/diagnostics.stderr
index 33f5337eb8072..7d038ff955d6c 100644
--- a/src/test/ui/const-generics/diagnostics.stderr
+++ b/src/test/ui/const-generics/diagnostics.stderr
@@ -41,8 +41,6 @@ error[E0747]: unresolved item provided when a constant was expected
 LL | impl<const N: u8> Foo for C<N, T> {}
    |                                ^
    |
-   = note: type arguments must be provided before constant arguments
-   = help: reorder the arguments: consts: `<C, N>`
 help: if this generic argument was intended as a const parameter, surround it with braces
    |
 LL | impl<const N: u8> Foo for C<N, { T }> {}