Skip to content

Commit

Permalink
Rollup merge of rust-lang#82055 - JulianKnodt:ty_where_const, r=estebank
Browse files Browse the repository at this point in the history
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``
  • Loading branch information
Dylan-DPC authored Feb 17, 2021
2 parents f5417bd + f520295 commit 8e87fe9
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 29 deletions.
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)),
..
}),
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 { .. },
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`

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 };
| ^ ^
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

0 comments on commit 8e87fe9

Please sign in to comment.