Skip to content

Account for associated type, const and static when using type argument #62004

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

Closed
wants to merge 2 commits into from
Closed
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
Binary file added single-use-lifetime-on-debug-struct
Binary file not shown.
33 changes: 33 additions & 0 deletions src/librustc_resolve/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,39 @@ use crate::{import_candidate_to_enum_paths, is_self_type, is_self_value, path_na
use crate::{AssocSuggestion, CrateLint, ImportSuggestion, ModuleOrUniformRoot, PathResult,
PathSource, Resolver, Segment, Suggestion};

#[derive(Clone, Copy)]
crate enum CurrentScope {
Const,
Static,
Type,
Other,
}

impl CurrentScope {
crate fn is_other(&self) -> bool {
match self {
CurrentScope::Other => true,
_ => false,
}
}

crate fn description(&self) -> &'static str {
match self {
Self::Const => "a `const`",
Self::Static => "a `static`",
Self::Type => "associated type",
Self::Other => "outer function",
}
}

crate fn generic_param_resolution_error_message(&self) -> String {
match self {
Self::Other => format!("from {}", self.description()),
_ => format!("in {}", self.description()),
}
}
}

impl<'a> Resolver<'a> {
/// Handles error reporting for `smart_resolve_path_fragment` function.
/// Creates base error and amends it with one short label and possibly some longer helps/notes.
Expand Down
49 changes: 43 additions & 6 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ use rustc_data_structures::ptr_key::PtrKey;
use rustc_data_structures::sync::Lrc;
use smallvec::SmallVec;

use diagnostics::{find_span_of_binding_until_next_binding, extend_span_to_previous_binding};
use diagnostics::{
find_span_of_binding_until_next_binding, extend_span_to_previous_binding, CurrentScope,
};
use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver};
use macros::{InvocationData, LegacyBinding, ParentScope};

Expand Down Expand Up @@ -210,14 +212,21 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>,
-> DiagnosticBuilder<'sess> {
match resolution_error {
ResolutionError::GenericParamsFromOuterFunction(outer_res) => {
let msg = resolver.scope.generic_param_resolution_error_message();
let mut err = struct_span_err!(resolver.session,
span,
E0401,
"can't use generic parameters from outer function",
"can't use generic parameters {}",
msg,
);
err.span_label(span, format!("use of generic parameter from outer function"));
err.span_label(span, &format!("use of generic parameter {}", msg));

let cm = resolver.session.source_map();
let type_param_extra_msg = if resolver.scope.is_other() {
"from outer function "
} else {
""
};
match outer_res {
Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => {
if let Some(impl_span) = maybe_impl_defid.and_then(|def_id| {
Expand All @@ -241,12 +250,18 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>,
},
Res::Def(DefKind::TyParam, def_id) => {
if let Some(span) = resolver.definitions.opt_span(def_id) {
err.span_label(span, "type parameter from outer function");
err.span_label(span, format!(
"type parameter {}being used",
type_param_extra_msg,
));
}
}
Res::Def(DefKind::ConstParam, def_id) => {
if let Some(span) = resolver.definitions.opt_span(def_id) {
err.span_label(span, "const parameter from outer function");
err.span_label(span, format!(
"const parameter {}being used",
type_param_extra_msg,
));
}
}
_ => {
Expand All @@ -258,7 +273,14 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>,
// Try to retrieve the span of the function signature and generate a new message with
// a local type or const parameter.
let sugg_msg = &format!("try using a local generic parameter instead");
if let Some((sugg_span, new_snippet)) = cm.generate_local_type_param_snippet(span) {
if !resolver.scope.is_other() {
err.help(&format!(
"{} need a type instead of a generic parameter",
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
"{} need a type instead of a generic parameter",
"{} needs a type instead of a generic parameter",

resolver.scope.description(),
));
} else if let Some(
(sugg_span, new_snippet),
) = cm.generate_local_type_param_snippet(span) {
// Suggest the modification to the user
err.span_suggestion(
sugg_span,
Expand All @@ -267,6 +289,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>,
Applicability::MachineApplicable,
);
} else if let Some(sp) = cm.generate_fn_name_span(span) {
// FIXME: needs to use proper scope navigation to avoid errors like #45447
err.span_label(sp,
format!("try adding a local generic parameter in this method instead"));
} else {
Expand Down Expand Up @@ -1688,6 +1711,9 @@ pub struct Resolver<'a> {
current_type_ascription: Vec<Span>,

injected_crate: Option<Module<'a>>,

/// Used for more accurate error when using type parameters in a associated items.
scope: CurrentScope,
Copy link
Contributor

Choose a reason for hiding this comment

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

Please use some other terminology than "scope", it's incredibly overloaded in resolve.
Also, could you move enum CurrentScope and its impls into diagnostics.rs?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What would be a better name?

Copy link
Member

Choose a reason for hiding this comment

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

BodyOwner / DefOwner maybe? (though Def is similarly unfortunately overloaded)

}

/// Nothing really interesting here; it just provides memory for the rest of the crate.
Expand Down Expand Up @@ -2013,6 +2039,7 @@ impl<'a> Resolver<'a> {
unused_macros: FxHashSet::default(),
current_type_ascription: Vec::new(),
injected_crate: None,
scope: CurrentScope::Other,
}
}

Expand Down Expand Up @@ -2520,6 +2547,8 @@ impl<'a> Resolver<'a> {

match item.node {
ItemKind::Ty(_, ref generics) => {
let scope = self.scope;
self.scope = CurrentScope::Type;
self.with_current_self_item(item, |this| {
this.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
let item_def_id = this.definitions.local_def_id(item.id);
Expand All @@ -2528,6 +2557,7 @@ impl<'a> Resolver<'a> {
})
})
});
self.scope = scope;
}

ItemKind::Existential(_, ref generics) |
Expand Down Expand Up @@ -2611,13 +2641,20 @@ impl<'a> Resolver<'a> {

ItemKind::Static(ref ty, _, ref expr) |
ItemKind::Const(ref ty, ref expr) => {
let scope = self.scope;
self.scope = match item.node {
ItemKind::Static(..) => CurrentScope::Static,
ItemKind::Const(..) => CurrentScope::Const,
_ => unreachable!(),
};
debug!("resolve_item ItemKind::Const");
self.with_item_rib(|this| {
this.visit_ty(ty);
this.with_constant_rib(|this| {
this.visit_expr(expr);
});
});
self.scope = scope;
}

ItemKind::Use(ref use_tree) => {
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/bad/bad-type-env-capture.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0401]: can't use generic parameters from outer function
--> $DIR/bad-type-env-capture.rs:2:15
|
LL | fn foo<T>() {
| - type parameter from outer function
| - type parameter from outer function being used
LL | fn bar(b: T) { }
| --- ^ use of generic parameter from outer function
| |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ error[E0401]: can't use generic parameters from outer function
--> $DIR/const-param-from-outer-fn.rs:6:9
|
LL | fn foo<const X: u32>() {
| - const parameter from outer function
| - const parameter from outer function being used
LL | fn bar() -> u32 {
| --- try adding a local generic parameter in this method instead
LL | X
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/error-codes/E0401.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0401]: can't use generic parameters from outer function
--> $DIR/E0401.rs:4:39
|
LL | fn foo<T>(x: T) {
| - type parameter from outer function
| - type parameter from outer function being used
LL | fn bfnr<U, V: Baz<U>, W: Fn()>(y: T) {
| --------------------------- ^ use of generic parameter from outer function
| |
Expand All @@ -12,7 +12,7 @@ error[E0401]: can't use generic parameters from outer function
--> $DIR/E0401.rs:9:16
|
LL | fn foo<T>(x: T) {
| - type parameter from outer function
| - type parameter from outer function being used
...
LL | fn baz<U,
| --- try adding a local generic parameter in this method instead
Expand Down
2 changes: 1 addition & 1 deletion src/test/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 in a `static`
}

fn main() {
Expand Down
10 changes: 5 additions & 5 deletions src/test/ui/inner-static-type-parameter.stderr
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 in a `static`
--> $DIR/inner-static-type-parameter.rs:6:19
|
LL | fn foo<T>() {
| --- - type parameter from outer function
| |
| try adding a local generic parameter in this method instead
| - type parameter being used
LL | static a: Bar<T> = Bar::What;
| ^ use of generic parameter from outer function
| ^ use of generic parameter in a `static`
|
= help: a `static` need a type instead of a generic parameter

error[E0392]: parameter `T` is never used
--> $DIR/inner-static-type-parameter.rs:3:10
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-3021-c.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0401]: can't use generic parameters from outer function
--> $DIR/issue-3021-c.rs:4:24
|
LL | fn siphash<T>() {
| - type parameter from outer function
| - type parameter from outer function being used
...
LL | fn g(&self, x: T) -> T;
| - ^ use of generic parameter from outer function
Expand All @@ -13,7 +13,7 @@ error[E0401]: can't use generic parameters from outer function
--> $DIR/issue-3021-c.rs:4:30
|
LL | fn siphash<T>() {
| - type parameter from outer function
| - type parameter from outer function being used
...
LL | fn g(&self, x: T) -> T;
| - ^ use of generic parameter from outer function
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-3214.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0401]: can't use generic parameters from outer function
--> $DIR/issue-3214.rs:3:12
|
LL | fn foo<T>() {
| --- - type parameter from outer function
| --- - type parameter from outer function being used
| |
| try adding a local generic parameter in this method instead
LL | struct Foo {
Expand Down
10 changes: 10 additions & 0 deletions src/test/ui/issues/issue-45447.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
trait Foo { const FOO: Self; }
impl Foo for u32 { const FOO: Self = 1; }
fn bar<T: Foo>(n: T) {
const BASE: T = T::FOO;
//~^ ERROR can't use generic parameters in a `const`
//~| ERROR can't use generic parameters in a `const`
type Type = T;
//~^ ERROR can't use generic parameters in associated type
Copy link
Contributor

Choose a reason for hiding this comment

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

Here Type is not an associated type alias but rather a free type alias.

}
fn main() {}
34 changes: 34 additions & 0 deletions src/test/ui/issues/issue-45447.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
error[E0401]: can't use generic parameters in a `const`
--> $DIR/issue-45447.rs:4:17
|
LL | fn bar<T: Foo>(n: T) {
| - type parameter being used
LL | const BASE: T = T::FOO;
| ^ use of generic parameter in a `const`
|
= help: a `const` need a type instead of a generic parameter

error[E0401]: can't use generic parameters in a `const`
--> $DIR/issue-45447.rs:4:21
|
LL | fn bar<T: Foo>(n: T) {
| - type parameter being used
LL | const BASE: T = T::FOO;
| ^^^^^^ use of generic parameter in a `const`
|
= help: a `const` need a type instead of a generic parameter

error[E0401]: can't use generic parameters in associated type
--> $DIR/issue-45447.rs:7:17
|
LL | fn bar<T: Foo>(n: T) {
| - type parameter being used
...
LL | type Type = T;
| ^ use of generic parameter in associated type
|
= help: associated type need a type instead of a generic parameter

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0401`.
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-5997-enum.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0401]: can't use generic parameters from outer function
--> $DIR/issue-5997-enum.rs:2:16
|
LL | fn f<Z>() -> bool {
| - - type parameter from outer function
| - - type parameter from outer function being used
| |
| try adding a local generic parameter in this method instead
LL | enum E { V(Z) }
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/issues/issue-5997-struct.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0401]: can't use generic parameters from outer function
--> $DIR/issue-5997-struct.rs:2:14
|
LL | fn f<T>() -> bool {
| - - type parameter from outer function
| - - type parameter from outer function being used
| |
| try adding a local generic parameter in this method instead
LL | struct S(T);
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/nested-ty-params.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0401]: can't use generic parameters from outer function
--> $DIR/nested-ty-params.rs:3:16
|
LL | fn hd<U>(v: Vec<U> ) -> U {
| - type parameter from outer function
| - type parameter from outer function being used
LL | fn hd1(w: [U]) -> U { return w[0]; }
| --- ^ use of generic parameter from outer function
| |
Expand All @@ -12,7 +12,7 @@ error[E0401]: can't use generic parameters from outer function
--> $DIR/nested-ty-params.rs:3:23
|
LL | fn hd<U>(v: Vec<U> ) -> U {
| - type parameter from outer function
| - type parameter from outer function being used
LL | fn hd1(w: [U]) -> U { return w[0]; }
| --- ^ use of generic parameter from outer function
| |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ error[E0401]: can't use generic parameters from outer function
--> $DIR/resolve-type-param-in-item-in-trait.rs:8:22
|
LL | trait TraitA<A> {
| - type parameter from outer function
| - type parameter from outer function being used
LL | fn outer(&self) {
| ----- try adding a local generic parameter in this method instead
LL | enum Foo<B> {
Expand All @@ -13,7 +13,7 @@ error[E0401]: can't use generic parameters from outer function
--> $DIR/resolve-type-param-in-item-in-trait.rs:16:23
|
LL | trait TraitB<A> {
| - type parameter from outer function
| - type parameter from outer function being used
LL | fn outer(&self) {
| ----- try adding a local generic parameter in this method instead
LL | struct Foo<B>(A);
Expand All @@ -23,7 +23,7 @@ error[E0401]: can't use generic parameters from outer function
--> $DIR/resolve-type-param-in-item-in-trait.rs:23:28
|
LL | trait TraitC<A> {
| - type parameter from outer function
| - type parameter from outer function being used
LL | fn outer(&self) {
| ----- try adding a local generic parameter in this method instead
LL | struct Foo<B> { a: A }
Expand All @@ -33,7 +33,7 @@ error[E0401]: can't use generic parameters from outer function
--> $DIR/resolve-type-param-in-item-in-trait.rs:30:22
|
LL | trait TraitD<A> {
| - type parameter from outer function
| - type parameter from outer function being used
LL | fn outer(&self) {
LL | fn foo<B>(a: A) { }
| ------ ^ use of generic parameter from outer function
Expand Down
Loading