Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve diagnostic for generic params from outer items (E0401) #115744

Merged
merged 3 commits into from
Sep 11, 2023
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
6 changes: 3 additions & 3 deletions compiler/rustc_error_codes/src/error_codes/E0401.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Inner items do not inherit type or const parameters from the functions
Inner items do not inherit the generic parameters from the items
they are embedded in.

Erroneous code example:
Expand Down Expand Up @@ -32,8 +32,8 @@ fn foo<T>(x: T) {
}
```

Items inside functions are basically just like top-level items, except
that they can only be used from the function they are in.
Items nested inside other items are basically just like top-level items, except
that they can only be used from the item they are in.

There are a couple of solutions for this.

Expand Down
29 changes: 13 additions & 16 deletions compiler/rustc_resolve/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,6 @@ resolve_cannot_find_ident_in_this_scope =
resolve_cannot_glob_import_possible_crates =
cannot glob-import all possible crates

resolve_cannot_use_self_type_here =
can't use `Self` here

resolve_change_import_binding =
you can use `as` to change the binding name of the import

Expand All @@ -86,9 +83,6 @@ resolve_const_not_member_of_trait =
const `{$const_}` is not a member of trait `{$trait_}`
.label = not a member of trait `{$trait_}`

resolve_const_param_from_outer_fn =
const parameter from outer function

resolve_const_param_in_enum_discriminant =
const parameters may not be used in enum discriminant values

Expand All @@ -115,10 +109,19 @@ resolve_forward_declared_generic_param =
generic parameters with a default cannot use forward declared identifiers
.label = defaulted generic parameters cannot be forward declared

resolve_generic_params_from_outer_function =
can't use generic parameters from outer function
.label = use of generic parameter from outer function
.suggestion = try using a local generic parameter instead
resolve_generic_params_from_outer_item =
can't use generic parameters from outer item
.label = use of generic parameter from outer item
.refer_to_type_directly = refer to the type directly here instead
.suggestion = try introducing a local generic parameter here

resolve_generic_params_from_outer_item_const_param = const parameter from outer item

resolve_generic_params_from_outer_item_self_ty_alias = `Self` type implicitly declared here, by this `impl`

resolve_generic_params_from_outer_item_self_ty_param = can't use `Self` here

resolve_generic_params_from_outer_item_ty_param = type parameter from outer item

resolve_glob_import_doesnt_reexport =
glob import doesn't reexport anything because no candidate is public enough
Expand Down Expand Up @@ -273,9 +276,6 @@ resolve_type_not_member_of_trait =
type `{$type_}` is not a member of trait `{$trait_}`
.label = not a member of trait `{$trait_}`

resolve_type_param_from_outer_fn =
type parameter from outer function

resolve_type_param_in_enum_discriminant =
type parameters may not be used in enum discriminant values

Expand Down Expand Up @@ -311,9 +311,6 @@ resolve_unreachable_label_suggestion_use_similarly_named =
resolve_unreachable_label_with_similar_name_exists =
a label with a similar name exists but is unreachable

resolve_use_a_type_here_instead =
use a type here instead

resolve_variable_bound_with_different_mode =
variable `{$variable_name}` is bound inconsistently across alternatives separated by `|`
.label = bound in different ways
Expand Down
47 changes: 20 additions & 27 deletions compiler/rustc_resolve/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -553,53 +553,47 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
resolution_error: ResolutionError<'a>,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
match resolution_error {
ResolutionError::GenericParamsFromOuterFunction(outer_res, has_generic_params) => {
let mut err = struct_span_err!(
self.tcx.sess,
ResolutionError::GenericParamsFromOuterItem(outer_res, has_generic_params) => {
use errs::GenericParamsFromOuterItemLabel as Label;
let mut err = errs::GenericParamsFromOuterItem {
span,
E0401,
"can't use generic parameters from outer function",
);
err.span_label(span, "use of generic parameter from outer function");
label: None,
refer_to_type_directly: None,
sugg: None,
};

let sm = self.tcx.sess.source_map();
let def_id = match outer_res {
Res::SelfTyParam { .. } => {
err.span_label(span, "can't use `Self` here");
return err;
err.label = Some(Label::SelfTyParam(span));
return self.tcx.sess.create_err(err);
}
Res::SelfTyAlias { alias_to: def_id, .. } => {
err.span_label(
reduce_impl_span_to_impl_keyword(sm, self.def_span(def_id)),
"`Self` type implicitly declared here, by this `impl`",
);
err.span_label(span, "use a type here instead");
return err;
err.label = Some(Label::SelfTyAlias(reduce_impl_span_to_impl_keyword(
sm,
self.def_span(def_id),
)));
err.refer_to_type_directly = Some(span);
return self.tcx.sess.create_err(err);
}
Res::Def(DefKind::TyParam, def_id) => {
err.span_label(self.def_span(def_id), "type parameter from outer function");
err.label = Some(Label::TyParam(self.def_span(def_id)));
def_id
}
Res::Def(DefKind::ConstParam, def_id) => {
err.span_label(
self.def_span(def_id),
"const parameter from outer function",
);
err.label = Some(Label::ConstParam(self.def_span(def_id)));
def_id
}
_ => {
bug!(
"GenericParamsFromOuterFunction should only be used with \
"GenericParamsFromOuterItem should only be used with \
Res::SelfTyParam, Res::SelfTyAlias, DefKind::TyParam or \
DefKind::ConstParam"
);
}
};

if let HasGenericParams::Yes(span) = has_generic_params {
// Try to retrieve the span of the function signature and generate a new
// message with a local type or const parameter.
let sugg_msg = "try using a local generic parameter instead";
let name = self.tcx.item_name(def_id);
let (span, snippet) = if span.is_empty() {
let snippet = format!("<{name}>");
Expand All @@ -609,11 +603,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let snippet = format!("{name}, ");
(span, snippet)
};
// Suggest the modification to the user
err.span_suggestion(span, sugg_msg, snippet, Applicability::MaybeIncorrect);
err.sugg = Some(errs::GenericParamsFromOuterItemSugg { span, snippet });
}

err
self.tcx.sess.create_err(err)
}
ResolutionError::NameAlreadyUsedInParameterList(name, first_use_span) => self
.tcx
Expand Down
34 changes: 34 additions & 0 deletions compiler/rustc_resolve/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,40 @@ pub(crate) struct CrateRootNamesMustBeNamedExplicitly(#[primary_span] pub(crate)
#[diag(resolve_crate_root_imports_must_be_named_explicitly)]
pub(crate) struct ResolutionError(#[primary_span] pub(crate) Span);

#[derive(Diagnostic)]
#[diag(resolve_generic_params_from_outer_item, code = "E0401")]
pub(crate) struct GenericParamsFromOuterItem {
#[primary_span]
#[label]
pub(crate) span: Span,
#[subdiagnostic]
pub(crate) label: Option<GenericParamsFromOuterItemLabel>,
#[label(resolve_refer_to_type_directly)]
pub(crate) refer_to_type_directly: Option<Span>,
#[subdiagnostic]
pub(crate) sugg: Option<GenericParamsFromOuterItemSugg>,
}

#[derive(Subdiagnostic)]
pub(crate) enum GenericParamsFromOuterItemLabel {
#[label(resolve_generic_params_from_outer_item_self_ty_param)]
SelfTyParam(#[primary_span] Span),
#[label(resolve_generic_params_from_outer_item_self_ty_alias)]
SelfTyAlias(#[primary_span] Span),
#[label(resolve_generic_params_from_outer_item_ty_param)]
TyParam(#[primary_span] Span),
#[label(resolve_generic_params_from_outer_item_const_param)]
ConstParam(#[primary_span] Span),
}

#[derive(Subdiagnostic)]
#[suggestion(resolve_suggestion, code = "{snippet}", applicability = "maybe-incorrect")]
pub(crate) struct GenericParamsFromOuterItemSugg {
#[primary_span]
pub(crate) span: Span,
pub(crate) snippet: String,
}

#[derive(Diagnostic)]
#[diag(resolve_name_is_already_used_as_generic_parameter, code = "E0403")]
pub(crate) struct NameAlreadyUsedInParameterList {
Expand Down
10 changes: 2 additions & 8 deletions compiler/rustc_resolve/src/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1229,10 +1229,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if let Some(span) = finalize {
self.report_error(
span,
ResolutionError::GenericParamsFromOuterFunction(
res,
has_generic_params,
),
ResolutionError::GenericParamsFromOuterItem(res, has_generic_params),
);
}
return Res::Err;
Expand Down Expand Up @@ -1296,10 +1293,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if let Some(span) = finalize {
self.report_error(
span,
ResolutionError::GenericParamsFromOuterFunction(
res,
has_generic_params,
),
ResolutionError::GenericParamsFromOuterItem(res, has_generic_params),
);
}
return Res::Err;
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2450,7 +2450,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
ItemKind::Const(box ast::ConstItem { ref generics, ref ty, ref expr, .. }) => {
self.with_generic_param_rib(
&generics.params,
RibKind::Item(HasGenericParams::Yes(generics.span)),
RibKind::Item(if self.r.tcx.features().generic_const_items {
HasGenericParams::Yes(generics.span)
} else {
HasGenericParams::No
}),
LifetimeRibKind::Generics {
binder: item.id,
kind: LifetimeBinderKind::ConstItem,
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_resolve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,8 @@ struct BindingError {

#[derive(Debug)]
enum ResolutionError<'a> {
/// Error E0401: can't use type or const parameters from outer function.
GenericParamsFromOuterFunction(Res, HasGenericParams),
/// Error E0401: can't use type or const parameters from outer item.
GenericParamsFromOuterItem(Res, HasGenericParams),
/// Error E0403: the name is already used for a type or const parameter in this generic
/// parameter list.
NameAlreadyUsedInParameterList(Symbol, Span),
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/const-generics/early/const-param-from-outer-fn.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
fn foo<const X: u32>() {
fn bar() -> u32 {
X //~ ERROR can't use generic parameters from outer function
X //~ ERROR can't use generic parameters from outer item
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
error[E0401]: can't use generic parameters from outer function
error[E0401]: can't use generic parameters from outer item
--> $DIR/const-param-from-outer-fn.rs:3:9
|
LL | fn foo<const X: u32>() {
| - const parameter from outer function
| - const parameter from outer item
LL | fn bar() -> u32 {
| - help: try using a local generic parameter instead: `<X>`
| - help: try introducing a local generic parameter here: `<X>`
LL | X
| ^ use of generic parameter from outer function
| ^ use of generic parameter from outer item

error: aborting due to previous error

Expand Down
22 changes: 11 additions & 11 deletions tests/ui/error-codes/E0401.stderr
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
error[E0401]: can't use generic parameters from outer function
error[E0401]: can't use generic parameters from outer item
--> $DIR/E0401.rs:4:39
|
LL | fn foo<T>(x: T) {
| - type parameter from outer function
| - type parameter from outer item
LL | fn bfnr<U, V: Baz<U>, W: Fn()>(y: T) {
| - ^ use of generic parameter from outer function
| - ^ use of generic parameter from outer item
| |
| help: try using a local generic parameter instead: `T,`
| help: try introducing a local generic parameter here: `T,`

error[E0401]: can't use generic parameters from outer function
error[E0401]: can't use generic parameters from outer item
--> $DIR/E0401.rs:9:16
|
LL | fn foo<T>(x: T) {
| - type parameter from outer function
| - type parameter from outer item
...
LL | fn baz<U,
| - help: try using a local generic parameter instead: `T,`
| - help: try introducing a local generic parameter here: `T,`
...
LL | (y: T) {
| ^ use of generic parameter from outer function
| ^ use of generic parameter from outer item

error[E0401]: can't use generic parameters from outer function
error[E0401]: can't use generic parameters from outer item
--> $DIR/E0401.rs:24:25
|
LL | impl<T> Iterator for A<T> {
Expand All @@ -29,8 +29,8 @@ LL | impl<T> Iterator for A<T> {
LL | fn helper(sel: &Self) -> u8 {
| ^^^^
| |
| use of generic parameter from outer function
| use a type here instead
| use of generic parameter from outer item
| refer to the type directly here instead

error[E0282]: type annotations needed
--> $DIR/E0401.rs:11:5
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/generics/issue-94432-garbage-ice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

fna<e>(){fnp(){e}} //~ ERROR unknown start of token: \u{fffd}
//~^ ERROR unknown start of token: \u{fffd}
//~^^ ERROR can't use generic parameters from outer function [E0401]
//~^^ ERROR can't use generic parameters from outer item [E0401]
//~^^^ WARN type parameter `e` should have an upper camel case name

fn main(){}
2 changes: 1 addition & 1 deletion tests/ui/generics/issue-98432.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ struct Struct<T>(T);

impl<T> Struct<T> {
const CONST: fn() = || {
struct _Obligation where T:; //~ ERROR can't use generic parameters from outer function
struct _Obligation where T:; //~ ERROR can't use generic parameters from outer item
};
}

Expand Down
8 changes: 4 additions & 4 deletions tests/ui/generics/issue-98432.stderr
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
error[E0401]: can't use generic parameters from outer function
error[E0401]: can't use generic parameters from outer item
--> $DIR/issue-98432.rs:5:34
|
LL | impl<T> Struct<T> {
| - type parameter from outer function
| - type parameter from outer item
LL | const CONST: fn() = || {
LL | struct _Obligation where T:;
| - ^ use of generic parameter from outer function
| - ^ use of generic parameter from outer item
| |
| help: try using a local generic parameter instead: `<T>`
| help: try introducing a local generic parameter here: `<T>`

error: aborting due to previous error

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/inner-static-type-parameter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ enum Bar<T> { What } //~ ERROR parameter `T` is never used

fn foo<T>() {
static a: Bar<T> = Bar::What;
//~^ ERROR can't use generic parameters from outer function
//~^ ERROR can't use generic parameters from outer item
}

fn main() {
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/inner-static-type-parameter.stderr
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
error[E0401]: can't use generic parameters from outer function
error[E0401]: can't use generic parameters from outer item
--> $DIR/inner-static-type-parameter.rs:6:19
|
LL | fn foo<T>() {
| - type parameter from outer function
| - type parameter from outer item
LL | static a: Bar<T> = Bar::What;
| ^ use of generic parameter from outer function
| ^ use of generic parameter from outer item

error[E0392]: parameter `T` is never used
--> $DIR/inner-static-type-parameter.rs:3:10
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/issues/issue-3214.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
fn foo<T>() {
struct Foo {
x: T, //~ ERROR can't use generic parameters from outer function
x: T, //~ ERROR can't use generic parameters from outer item
}

impl<T> Drop for Foo<T> {
Expand Down
Loading
Loading