From be1ed00712ce0b884e1fc9779f25b1758e994d0b Mon Sep 17 00:00:00 2001 From: kadmin 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, ¶m.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; +trait Foo {} +impl Foo for A {} +//~^ ERROR type provided when a constant +//~| ERROR cannot find type + +struct B; +impl Foo for B {} +//~^ 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; + | ---------------------- similarly named struct `A` defined here +LL | trait Foo {} +LL | impl Foo for A {} + | ^ 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 {} + | ^ + +error[E0747]: type provided when a constant was expected + --> $DIR/diagnostics.rs:12:19 + | +LL | impl Foo for B {} + | - ^ + | | + | 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 = 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 { 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::(); | ^^^^^^^^^^^^^^ - | -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 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, ¶m.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() -> Foo { | ^ | -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() -> 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; trait Foo {} impl Foo for A {} -//~^ ERROR type provided when a constant -//~| ERROR cannot find type +//~^ ERROR cannot find type +//~| unresolved item provided when a constant struct B; impl Foo for B {} //~^ ERROR type provided when a constant + +struct C; +impl Foo for C {} +//~^ 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 {} | ^ 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; + | ---------------------- similarly named struct `A` defined here +... +LL | impl Foo for C {} + | ^ 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 {} | ^ + | +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 Foo for B {} | - ^ | | - | 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 Foo for C {} + | ^ + | + = note: type arguments must be provided before constant arguments + = help: reorder the arguments: consts: `` +help: if this generic argument was intended as a const parameter, surround it with braces + | +LL | impl Foo for C {} + | ^ ^ -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() {} pub fn test_2(x: T) {} pub struct Example{ - x: T, + x: T, } impl Example { @@ -20,15 +20,15 @@ impl Example { pub fn main() { test_1::(); //~^ 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 = 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 { 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 = 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 = 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 { 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::(); | ^^^^^^^^^^^^^^ + | +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 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 Foo for C {} | ^ | - = note: type arguments must be provided before constant arguments - = help: reorder the arguments: consts: `` help: if this generic argument was intended as a const parameter, surround it with braces | LL | impl Foo for C {}