about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_typeck/src/astconv/generics.rs65
-rw-r--r--src/test/ui/const-generics/const-param-shadowing.stderr2
-rw-r--r--src/test/ui/const-generics/diagnostics.rs18
-rw-r--r--src/test/ui/const-generics/diagnostics.stderr52
-rw-r--r--src/test/ui/const-generics/invalid-enum.rs12
-rw-r--r--src/test/ui/const-generics/invalid-enum.stderr14
6 files changed, 134 insertions, 29 deletions
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index 67e37ca8d8e..0ea0ccaceab 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::{
@@ -43,23 +44,57 @@ 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) {
             (
-                GenericArg::Type(hir::Ty { kind: hir::TyKind::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,
-                );
-            }
+                GenericArg::Type(hir::Ty {
+                    kind: hir::TyKind::Path(rustc_hir::QPath::Resolved(_, path)),
+                    ..
+                }),
+                GenericParamDefKind::Const,
+            ) => match path.res {
+                Res::Err => {
+                    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() {
+                        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),
+                                "consider changing this type paramater to a `const`-generic",
+                                format!("const {}: {}", param_name, param_type),
+                                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 7447ca3ff36..17ccd2f3527 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
new file mode 100644
index 00000000000..1581af5ab27
--- /dev/null
+++ b/src/test/ui/const-generics/diagnostics.rs
@@ -0,0 +1,18 @@
+#![crate_type="lib"]
+#![feature(min_const_generics)]
+#![allow(incomplete_features)]
+
+struct A<const N: u8>;
+trait Foo {}
+impl Foo for A<N> {}
+//~^ 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
new file mode 100644
index 00000000000..7d038ff955d
--- /dev/null
+++ b/src/test/ui/const-generics/diagnostics.stderr
@@ -0,0 +1,52 @@
+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[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
+   |
+LL | impl<N> Foo for B<N> {}
+   |      -            ^
+   |      |
+   |      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> {}
+   |                                ^
+   |
+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 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 4ca10ed8b71..32939dcd286 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 7822fc072e3..cfbc61f0254 100644
--- a/src/test/ui/const-generics/invalid-enum.stderr
+++ b/src/test/ui/const-generics/invalid-enum.stderr
@@ -25,13 +25,13 @@ 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, try surrounding it with braces:
+help: if this generic argument was intended as a const parameter, surround it with braces
    |
 LL |   let _: Example<{ CompileFlag::A }, _> = Example { x: 0 };
    |                  ^                ^
@@ -42,29 +42,29 @@ error[E0747]: type provided when a constant was expected
 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:
+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, try surrounding it with braces:
+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, try surrounding it with braces:
+help: if this generic argument was intended as a const parameter, surround it with braces
    |
 LL |   test_2::<_, { CompileFlag::A }>(0);
    |               ^                ^