diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 1b1198af41c0e..a8a78854d7293 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -573,12 +573,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { span, label: None, refer_to_type_directly: None, + use_let: None, sugg: None, static_or_const, is_self, - item: inner_item.as_ref().map(|(span, kind)| { + item: inner_item.as_ref().map(|(label_span, _, kind)| { errs::GenericParamsFromOuterItemInnerItem { - span: *span, + span: *label_span, descr: kind.descr().to_string(), is_self, } @@ -586,10 +587,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; let sm = self.tcx.sess.source_map(); + // Note: do not early return for missing def_id here, + // we still want to provide suggestions for `Res::SelfTyParam` and `Res::SelfTyAlias`. let def_id = match outer_res { Res::SelfTyParam { .. } => { err.label = Some(Label::SelfTyParam(span)); - return self.dcx().create_err(err); + None } Res::SelfTyAlias { alias_to: def_id, .. } => { err.label = Some(Label::SelfTyAlias(reduce_impl_span_to_impl_keyword( @@ -598,15 +601,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ))); err.refer_to_type_directly = current_self_ty.map(|snippet| errs::UseTypeDirectly { span, snippet }); - return self.dcx().create_err(err); + None } Res::Def(DefKind::TyParam, def_id) => { err.label = Some(Label::TyParam(self.def_span(def_id))); - def_id + Some(def_id) } Res::Def(DefKind::ConstParam, def_id) => { err.label = Some(Label::ConstParam(self.def_span(def_id))); - def_id + Some(def_id) } _ => { bug!( @@ -617,8 +620,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } }; - if let HasGenericParams::Yes(span) = has_generic_params - && !matches!(inner_item, Some((_, ItemKind::Delegation(..)))) + if let Some((_, item_span, ItemKind::Const(_))) = inner_item.as_ref() { + err.use_let = Some(errs::GenericParamsFromOuterItemUseLet { + span: sm.span_until_whitespace(*item_span), + }); + } + + if let Some(def_id) = def_id + && let HasGenericParams::Yes(span) = has_generic_params + && !matches!(inner_item, Some((_, _, ItemKind::Delegation(..)))) { let name = self.tcx.item_name(def_id); let (span, snippet) = if span.is_empty() { diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 63ffdbc37f7d1..d09c76d7947a9 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -33,6 +33,8 @@ pub(crate) struct GenericParamsFromOuterItem { #[subdiagnostic] pub(crate) refer_to_type_directly: Option, #[subdiagnostic] + pub(crate) use_let: Option, + #[subdiagnostic] pub(crate) sugg: Option, #[subdiagnostic] pub(crate) static_or_const: Option, @@ -87,6 +89,19 @@ pub(crate) struct GenericParamsFromOuterItemSugg { pub(crate) span: Span, pub(crate) snippet: String, } + +#[derive(Subdiagnostic)] +#[suggestion( + "try using a local `let` binding instead", + code = "let", + applicability = "maybe-incorrect", + style = "verbose" +)] +pub(crate) struct GenericParamsFromOuterItemUseLet { + #[primary_span] + pub(crate) span: Span, +} + #[derive(Subdiagnostic)] #[suggestion( "refer to the type directly here instead", diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 7cfd5b5f861a4..56e77cdde91f1 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1582,12 +1582,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let item = if let Some(diag_metadata) = diag_metadata && let Some(current_item) = diag_metadata.current_item { - let span = current_item + let label_span = current_item .kind .ident() .map(|i| i.span) .unwrap_or(current_item.span); - Some((span, current_item.kind.clone())) + Some((label_span, current_item.span, current_item.kind.clone())) } else { None }; @@ -1679,12 +1679,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let item = if let Some(diag_metadata) = diag_metadata && let Some(current_item) = diag_metadata.current_item { - let span = current_item + let label_span = current_item .kind .ident() .map(|i| i.span) .unwrap_or(current_item.span); - Some((span, current_item.kind.clone())) + Some((label_span, current_item.span, current_item.kind.clone())) } else { None }; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index ead69473b00d1..3cd5c827693a4 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -247,7 +247,8 @@ enum ResolutionError<'ra> { outer_res: Res, has_generic_params: HasGenericParams, def_kind: DefKind, - inner_item: Option<(Span, ast::ItemKind)>, + /// 1. label span, 2. item span, 3. item kind + inner_item: Option<(Span, Span, ast::ItemKind)>, current_self_ty: Option, }, /// Error E0403: the name is already used for a type or const parameter in this generic diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr index 8827d1bbb49d3..21f80198f1978 100644 --- a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr +++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr @@ -10,9 +10,14 @@ LL | const K: u32 = T::C; | = note: nested items are independent from their parent item for everything except for privacy and name resolution = note: a `const` is a separate item from the item that contains it +help: try using a local `let` binding instead + | +LL - const K: u32 = T::C; +LL + let K: u32 = T::C; + | error[E0401]: can't use generic parameters from outer item - --> $DIR/generic-params-from-outer-item-in-const-item.rs:19:24 + --> $DIR/generic-params-from-outer-item-in-const-item.rs:20:24 | LL | impl Tr for T { // outer impl block | - type parameter from outer item @@ -24,9 +29,14 @@ LL | const I: u32 = T::C; | = note: nested items are independent from their parent item for everything except for privacy and name resolution = note: a `const` is a separate item from the item that contains it +help: try using a local `let` binding instead + | +LL - const I: u32 = T::C; +LL + let I: u32 = T::C; + | error[E0401]: can't use generic parameters from outer item - --> $DIR/generic-params-from-outer-item-in-const-item.rs:27:20 + --> $DIR/generic-params-from-outer-item-in-const-item.rs:29:20 | LL | struct S(U32<{ // outer struct | - type parameter from outer item @@ -37,6 +47,11 @@ LL | const _: u32 = T::C; | = note: nested items are independent from their parent item for everything except for privacy and name resolution = note: a `const` is a separate item from the item that contains it +help: try using a local `let` binding instead + | +LL - const _: u32 = T::C; +LL + let _: u32 = T::C; + | error: aborting due to 3 previous errors diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr index 8ff9771b9ade6..54a53a097bcbe 100644 --- a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr +++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr @@ -10,13 +10,18 @@ LL | const K: u32 = T::C; | = note: nested items are independent from their parent item for everything except for privacy and name resolution = note: a `const` is a separate item from the item that contains it +help: try using a local `let` binding instead + | +LL - const K: u32 = T::C; +LL + let K: u32 = T::C; + | help: try introducing a local generic parameter here | LL | const K: u32 = T::C; | +++ error[E0401]: can't use generic parameters from outer item - --> $DIR/generic-params-from-outer-item-in-const-item.rs:19:24 + --> $DIR/generic-params-from-outer-item-in-const-item.rs:20:24 | LL | impl Tr for T { // outer impl block | - type parameter from outer item @@ -28,13 +33,18 @@ LL | const I: u32 = T::C; | = note: nested items are independent from their parent item for everything except for privacy and name resolution = note: a `const` is a separate item from the item that contains it +help: try using a local `let` binding instead + | +LL - const I: u32 = T::C; +LL + let I: u32 = T::C; + | help: try introducing a local generic parameter here | LL | const I: u32 = T::C; | +++ error[E0401]: can't use generic parameters from outer item - --> $DIR/generic-params-from-outer-item-in-const-item.rs:27:20 + --> $DIR/generic-params-from-outer-item-in-const-item.rs:29:20 | LL | struct S(U32<{ // outer struct | - type parameter from outer item @@ -45,6 +55,11 @@ LL | const _: u32 = T::C; | = note: nested items are independent from their parent item for everything except for privacy and name resolution = note: a `const` is a separate item from the item that contains it +help: try using a local `let` binding instead + | +LL - const _: u32 = T::C; +LL + let _: u32 = T::C; + | help: try introducing a local generic parameter here | LL | const _: u32 = T::C; diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.rs b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.rs index c9a64de7f6bba..9616144ec3103 100644 --- a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.rs +++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.rs @@ -11,6 +11,7 @@ fn outer() { // outer function const K: u32 = T::C; //~^ ERROR can't use generic parameters from outer item + //~| HELP try using a local `let` binding instead //[generic_const_items]~| HELP try introducing a local generic parameter here } @@ -18,6 +19,7 @@ impl Tr for T { // outer impl block const C: u32 = { const I: u32 = T::C; //~^ ERROR can't use generic parameters from outer item + //~| HELP try using a local `let` binding instead //[generic_const_items]~| HELP try introducing a local generic parameter here I }; @@ -26,6 +28,7 @@ impl Tr for T { // outer impl block struct S(U32<{ // outer struct const _: u32 = T::C; //~^ ERROR can't use generic parameters from outer item + //~| HELP try using a local `let` binding instead //[generic_const_items]~| HELP try introducing a local generic parameter here 0 }>); diff --git a/tests/ui/resolve/generic-params-from-outer-item-suggestion.fixed b/tests/ui/resolve/generic-params-from-outer-item-suggestion.fixed new file mode 100644 index 0000000000000..fea9f7a6f8516 --- /dev/null +++ b/tests/ui/resolve/generic-params-from-outer-item-suggestion.fixed @@ -0,0 +1,39 @@ +// Regression test for . +// Ensure we provide a suggestion to change from `const` to `let` +// on the generic params from outer item errors. + +//@ run-rustfix + +#![allow(unused, non_snake_case)] + +const fn size_plus_one() -> usize { + //~^ NOTE type parameter from outer item + let size: usize = core::mem::size_of::(); + //~^ ERROR can't use generic parameters from outer item + //~| NOTE nested items are independent + //~| NOTE a `const` is a separate item + //~| NOTE use of generic parameter from outer item + //~| NOTE generic parameter used in this inner constant item + //~| HELP try using a local `let` binding instead + size + 1 +} + +struct A; + +impl A { + //~^ NOTE `Self` type implicitly declared here, by this `impl` + const VALUE: u32 = 1; + + fn f() { + let K: u32 = A::VALUE; + //~^ ERROR can't use `Self` from outer item + //~| NOTE use of `Self` from outer item + //~| NOTE `Self` used in this inner constant item + //~| NOTE nested items are independent + //~| NOTE a `const` is a separate item + //~| HELP refer to the type directly here instead + //~| HELP try using a local `let` binding instead + } +} + +fn main() {} diff --git a/tests/ui/resolve/generic-params-from-outer-item-suggestion.rs b/tests/ui/resolve/generic-params-from-outer-item-suggestion.rs new file mode 100644 index 0000000000000..3f87f3e2a2ae8 --- /dev/null +++ b/tests/ui/resolve/generic-params-from-outer-item-suggestion.rs @@ -0,0 +1,39 @@ +// Regression test for . +// Ensure we provide a suggestion to change from `const` to `let` +// on the generic params from outer item errors. + +//@ run-rustfix + +#![allow(unused, non_snake_case)] + +const fn size_plus_one() -> usize { + //~^ NOTE type parameter from outer item + const size: usize = core::mem::size_of::(); + //~^ ERROR can't use generic parameters from outer item + //~| NOTE nested items are independent + //~| NOTE a `const` is a separate item + //~| NOTE use of generic parameter from outer item + //~| NOTE generic parameter used in this inner constant item + //~| HELP try using a local `let` binding instead + size + 1 +} + +struct A; + +impl A { + //~^ NOTE `Self` type implicitly declared here, by this `impl` + const VALUE: u32 = 1; + + fn f() { + const K: u32 = Self::VALUE; + //~^ ERROR can't use `Self` from outer item + //~| NOTE use of `Self` from outer item + //~| NOTE `Self` used in this inner constant item + //~| NOTE nested items are independent + //~| NOTE a `const` is a separate item + //~| HELP refer to the type directly here instead + //~| HELP try using a local `let` binding instead + } +} + +fn main() {} diff --git a/tests/ui/resolve/generic-params-from-outer-item-suggestion.stderr b/tests/ui/resolve/generic-params-from-outer-item-suggestion.stderr new file mode 100644 index 0000000000000..3d3280cfbbb4b --- /dev/null +++ b/tests/ui/resolve/generic-params-from-outer-item-suggestion.stderr @@ -0,0 +1,46 @@ +error[E0401]: can't use generic parameters from outer item + --> $DIR/generic-params-from-outer-item-suggestion.rs:11:46 + | +LL | const fn size_plus_one() -> usize { + | - type parameter from outer item +LL | +LL | const size: usize = core::mem::size_of::(); + | ---- ^ use of generic parameter from outer item + | | + | generic parameter used in this inner constant item + | + = note: nested items are independent from their parent item for everything except for privacy and name resolution + = note: a `const` is a separate item from the item that contains it +help: try using a local `let` binding instead + | +LL - const size: usize = core::mem::size_of::(); +LL + let size: usize = core::mem::size_of::(); + | + +error[E0401]: can't use `Self` from outer item + --> $DIR/generic-params-from-outer-item-suggestion.rs:28:24 + | +LL | impl A { + | ---- `Self` type implicitly declared here, by this `impl` +... +LL | const K: u32 = Self::VALUE; + | - ^^^^ use of `Self` from outer item + | | + | `Self` used in this inner constant item + | + = note: nested items are independent from their parent item for everything except for privacy and name resolution + = note: a `const` is a separate item from the item that contains it +help: refer to the type directly here instead + | +LL - const K: u32 = Self::VALUE; +LL + const K: u32 = A::VALUE; + | +help: try using a local `let` binding instead + | +LL - const K: u32 = Self::VALUE; +LL + let K: u32 = Self::VALUE; + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0401`.