Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add diagnostics for specific cases for const/type mismatch err #82055

Merged
merged 3 commits into from
Feb 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 50 additions & 15 deletions compiler/rustc_typeck/src/astconv/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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)),
estebank marked this conversation as resolved.
Show resolved Hide resolved
..
}),
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() {
JulianKnodt marked this conversation as resolved.
Show resolved Hide resolved
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),
},
JulianKnodt marked this conversation as resolved.
Show resolved Hide resolved
(
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 { .. },
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/const-generics/const-param-shadowing.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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 }> {
| ^ ^
Expand Down
18 changes: 18 additions & 0 deletions src/test/ui/const-generics/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -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
52 changes: 52 additions & 0 deletions src/test/ui/const-generics/diagnostics.stderr
Original file line number Diff line number Diff line change
@@ -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`
Comment on lines +7 to +8
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally this would suggest "you meant to add a const N here and write this as A<{ N }>".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's hard to tell if a Res::Err is this case or the other case where the path was not given enough generic args


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`.
12 changes: 6 additions & 6 deletions src/test/ui/const-generics/invalid-enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand All @@ -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
Expand Down
14 changes: 7 additions & 7 deletions src/test/ui/const-generics/invalid-enum.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
| ^ ^
JulianKnodt marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -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);
| ^ ^
Expand Down