Skip to content
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
26 changes: 18 additions & 8 deletions compiler/rustc_resolve/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -573,23 +573,26 @@ 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,
}
}),
};

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(
Expand All @@ -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!(
Expand All @@ -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() {
Expand Down
15 changes: 15 additions & 0 deletions compiler/rustc_resolve/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ pub(crate) struct GenericParamsFromOuterItem {
#[subdiagnostic]
pub(crate) refer_to_type_directly: Option<UseTypeDirectly>,
#[subdiagnostic]
pub(crate) use_let: Option<GenericParamsFromOuterItemUseLet>,
#[subdiagnostic]
pub(crate) sugg: Option<GenericParamsFromOuterItemSugg>,
#[subdiagnostic]
pub(crate) static_or_const: Option<GenericParamsFromOuterItemStaticOrConst>,
Expand Down Expand Up @@ -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",
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_resolve/src/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
Expand Down Expand Up @@ -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
};
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_resolve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)>,
Copy link
Copy Markdown
Member

@wesleywiser wesleywiser Apr 30, 2026

Choose a reason for hiding this comment

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

We might want to turn this into a proper struct soon :)

View changes since the review

current_self_ty: Option<String>,
},
/// Error E0403: the name is already used for a type or const parameter in this generic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<T> Tr for T { // outer impl block
| - type parameter from outer item
Expand All @@ -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<T: Tr>(U32<{ // outer struct
| - type parameter from outer item
Expand All @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>: 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<T> Tr for T { // outer impl block
| - type parameter from outer item
Expand All @@ -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<T>: 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<T: Tr>(U32<{ // outer struct
| - type parameter from outer item
Expand All @@ -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 _<T>: u32 = T::C;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@
fn outer<T: Tr>() { // 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
}

impl<T> 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
};
Expand All @@ -26,6 +28,7 @@ impl<T> Tr for T { // outer impl block
struct S<T: Tr>(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
}>);
Expand Down
39 changes: 39 additions & 0 deletions tests/ui/resolve/generic-params-from-outer-item-suggestion.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Regression test for <https://github.com/rust-lang/rust/issues/68373>.
// 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<T:Sized>() -> usize {
//~^ NOTE type parameter from outer item
let size: usize = core::mem::size_of::<T>();
//~^ 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() {}
39 changes: 39 additions & 0 deletions tests/ui/resolve/generic-params-from-outer-item-suggestion.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Regression test for <https://github.com/rust-lang/rust/issues/68373>.
// 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<T:Sized>() -> usize {
//~^ NOTE type parameter from outer item
const size: usize = core::mem::size_of::<T>();
//~^ 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() {}
46 changes: 46 additions & 0 deletions tests/ui/resolve/generic-params-from-outer-item-suggestion.stderr
Original file line number Diff line number Diff line change
@@ -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<T:Sized>() -> usize {
| - type parameter from outer item
LL |
LL | const size: usize = core::mem::size_of::<T>();
| ---- ^ 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::<T>();
LL + let size: usize = core::mem::size_of::<T>();
|

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