Rollup merge of #82055 - JulianKnodt:ty_where_const, r=estebank

Add diagnostics for specific cases for const/type mismatch err

For now, this adds at least more information so better diagnostics can be emitted for const mismatch errors.

I'm not sure what exactly we want to emit, so I've left notes there temporarily, also to see if this is the right approach

r? ```@lcnr```
cc: ```@estebank```
This commit is contained in:
Yuki Okushi 2021-02-18 15:57:26 +09:00 committed by GitHub
commit 0c25d154bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 134 additions and 29 deletions

View File

@ -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 { .. },

View File

@ -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 }> {
| ^ ^

View File

@ -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

View File

@ -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`.

View File

@ -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

View File

@ -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);
| ^ ^