Skip to content

Commit 1e8945b

Browse files
committed
Account for associated type, const and static when using type argument
When using a type argument from the enclosing scope in an associated type, const or static item provide a more targetted E0401 error, instead of blaming the "outer function" blindly.
1 parent 088b987 commit 1e8945b

16 files changed

+140
-28
lines changed

single-use-lifetime-on-debug-struct

351 KB
Binary file not shown.

src/librustc_resolve/lib.rs

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,39 @@ enum ResolutionError<'a> {
194194
ConstParamDependentOnTypeParam,
195195
}
196196

197+
#[derive(Clone, Copy)]
198+
enum CurrentScope {
199+
Const,
200+
Static,
201+
Type,
202+
Other,
203+
}
204+
205+
impl CurrentScope {
206+
fn is_other(&self) -> bool {
207+
match self {
208+
CurrentScope::Other => true,
209+
_ => false,
210+
}
211+
}
212+
213+
fn description(&self) -> &'static str {
214+
match self {
215+
Self::Const => "`const` associated item",
216+
Self::Static => "`static` associated item",
217+
Self::Type => "associated type",
218+
Self::Other => "outer function",
219+
}
220+
}
221+
222+
fn generic_param_resolution_error_message(&self) -> String {
223+
match self {
224+
Self::Other => format!("from {}", self.description()),
225+
_ => format!("in {}", self.description()),
226+
}
227+
}
228+
}
229+
197230
/// Combines an error with provided span and emits it.
198231
///
199232
/// This takes the error provided, combines it with the span and any additional spans inside the
@@ -210,14 +243,21 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>,
210243
-> DiagnosticBuilder<'sess> {
211244
match resolution_error {
212245
ResolutionError::GenericParamsFromOuterFunction(outer_res) => {
246+
let msg = resolver.scope.generic_param_resolution_error_message();
213247
let mut err = struct_span_err!(resolver.session,
214248
span,
215249
E0401,
216-
"can't use generic parameters from outer function",
250+
"can't use generic parameters {}",
251+
msg,
217252
);
218-
err.span_label(span, format!("use of generic parameter from outer function"));
253+
err.span_label(span, &format!("use of generic parameter {}", msg));
219254

220255
let cm = resolver.session.source_map();
256+
let type_param_extra_msg = if resolver.scope.is_other() {
257+
"from outer function "
258+
} else {
259+
""
260+
};
221261
match outer_res {
222262
Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => {
223263
if let Some(impl_span) = maybe_impl_defid.and_then(|def_id| {
@@ -241,12 +281,18 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>,
241281
},
242282
Res::Def(DefKind::TyParam, def_id) => {
243283
if let Some(span) = resolver.definitions.opt_span(def_id) {
244-
err.span_label(span, "type parameter from outer function");
284+
err.span_label(span, format!(
285+
"type parameter {}being used",
286+
type_param_extra_msg,
287+
));
245288
}
246289
}
247290
Res::Def(DefKind::ConstParam, def_id) => {
248291
if let Some(span) = resolver.definitions.opt_span(def_id) {
249-
err.span_label(span, "const parameter from outer function");
292+
err.span_label(span, format!(
293+
"const parameter {}being used",
294+
type_param_extra_msg,
295+
));
250296
}
251297
}
252298
_ => {
@@ -258,7 +304,14 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>,
258304
// Try to retrieve the span of the function signature and generate a new message with
259305
// a local type or const parameter.
260306
let sugg_msg = &format!("try using a local generic parameter instead");
261-
if let Some((sugg_span, new_snippet)) = cm.generate_local_type_param_snippet(span) {
307+
if !resolver.scope.is_other() {
308+
err.help(&format!(
309+
"{} need a type instead of a generic parameter",
310+
resolver.scope.description(),
311+
));
312+
} else if let Some(
313+
(sugg_span, new_snippet),
314+
) = cm.generate_local_type_param_snippet(span) {
262315
// Suggest the modification to the user
263316
err.span_suggestion(
264317
sugg_span,
@@ -267,6 +320,7 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>,
267320
Applicability::MachineApplicable,
268321
);
269322
} else if let Some(sp) = cm.generate_fn_name_span(span) {
323+
// FIXME: needs to use proper scope navigation to avoid errors like #45447
270324
err.span_label(sp,
271325
format!("try adding a local generic parameter in this method instead"));
272326
} else {
@@ -1688,6 +1742,9 @@ pub struct Resolver<'a> {
16881742
current_type_ascription: Vec<Span>,
16891743

16901744
injected_crate: Option<Module<'a>>,
1745+
1746+
/// Used for more accurate error when using type parameters in a associated items.
1747+
scope: CurrentScope,
16911748
}
16921749

16931750
/// Nothing really interesting here; it just provides memory for the rest of the crate.
@@ -2013,6 +2070,7 @@ impl<'a> Resolver<'a> {
20132070
unused_macros: FxHashSet::default(),
20142071
current_type_ascription: Vec::new(),
20152072
injected_crate: None,
2073+
scope: CurrentScope::Other,
20162074
}
20172075
}
20182076

@@ -2520,6 +2578,8 @@ impl<'a> Resolver<'a> {
25202578

25212579
match item.node {
25222580
ItemKind::Ty(_, ref generics) => {
2581+
let scope = self.scope;
2582+
self.scope = CurrentScope::Type;
25232583
self.with_current_self_item(item, |this| {
25242584
this.with_generic_param_rib(HasGenericParams(generics, ItemRibKind), |this| {
25252585
let item_def_id = this.definitions.local_def_id(item.id);
@@ -2528,6 +2588,7 @@ impl<'a> Resolver<'a> {
25282588
})
25292589
})
25302590
});
2591+
self.scope = scope;
25312592
}
25322593

25332594
ItemKind::Existential(_, ref generics) |
@@ -2611,13 +2672,20 @@ impl<'a> Resolver<'a> {
26112672

26122673
ItemKind::Static(ref ty, _, ref expr) |
26132674
ItemKind::Const(ref ty, ref expr) => {
2675+
let scope = self.scope;
2676+
self.scope = match item.node {
2677+
ItemKind::Static(..) => CurrentScope::Static,
2678+
ItemKind::Const(..) => CurrentScope::Const,
2679+
_ => unreachable!(),
2680+
};
26142681
debug!("resolve_item ItemKind::Const");
26152682
self.with_item_rib(|this| {
26162683
this.visit_ty(ty);
26172684
this.with_constant_rib(|this| {
26182685
this.visit_expr(expr);
26192686
});
26202687
});
2688+
self.scope = scope;
26212689
}
26222690

26232691
ItemKind::Use(ref use_tree) => {

src/test/ui/bad/bad-type-env-capture.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0401]: can't use generic parameters from outer function
22
--> $DIR/bad-type-env-capture.rs:2:15
33
|
44
LL | fn foo<T>() {
5-
| - type parameter from outer function
5+
| - type parameter from outer function being used
66
LL | fn bar(b: T) { }
77
| --- ^ use of generic parameter from outer function
88
| |

src/test/ui/const-generics/const-param-from-outer-fn.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ error[E0401]: can't use generic parameters from outer function
88
--> $DIR/const-param-from-outer-fn.rs:6:9
99
|
1010
LL | fn foo<const X: u32>() {
11-
| - const parameter from outer function
11+
| - const parameter from outer function being used
1212
LL | fn bar() -> u32 {
1313
| --- try adding a local generic parameter in this method instead
1414
LL | X

src/test/ui/error-codes/E0401.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0401]: can't use generic parameters from outer function
22
--> $DIR/E0401.rs:4:39
33
|
44
LL | fn foo<T>(x: T) {
5-
| - type parameter from outer function
5+
| - type parameter from outer function being used
66
LL | fn bfnr<U, V: Baz<U>, W: Fn()>(y: T) {
77
| --------------------------- ^ use of generic parameter from outer function
88
| |
@@ -12,7 +12,7 @@ error[E0401]: can't use generic parameters from outer function
1212
--> $DIR/E0401.rs:9:16
1313
|
1414
LL | fn foo<T>(x: T) {
15-
| - type parameter from outer function
15+
| - type parameter from outer function being used
1616
...
1717
LL | fn baz<U,
1818
| --- try adding a local generic parameter in this method instead

src/test/ui/inner-static-type-parameter.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ enum Bar<T> { What } //~ ERROR parameter `T` is never used
44

55
fn foo<T>() {
66
static a: Bar<T> = Bar::What;
7-
//~^ ERROR can't use generic parameters from outer function
7+
//~^ ERROR can't use generic parameters in `static` associated item
88
}
99

1010
fn main() {

src/test/ui/inner-static-type-parameter.stderr

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
error[E0401]: can't use generic parameters from outer function
1+
error[E0401]: can't use generic parameters in `static` associated item
22
--> $DIR/inner-static-type-parameter.rs:6:19
33
|
44
LL | fn foo<T>() {
5-
| --- - type parameter from outer function
6-
| |
7-
| try adding a local generic parameter in this method instead
5+
| - type parameter being used
86
LL | static a: Bar<T> = Bar::What;
9-
| ^ use of generic parameter from outer function
7+
| ^ use of generic parameter in `static` associated item
8+
|
9+
= help: `static` associated item need a type instead of a generic parameter
1010

1111
error[E0392]: parameter `T` is never used
1212
--> $DIR/inner-static-type-parameter.rs:3:10

src/test/ui/issues/issue-3021-c.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0401]: can't use generic parameters from outer function
22
--> $DIR/issue-3021-c.rs:4:24
33
|
44
LL | fn siphash<T>() {
5-
| - type parameter from outer function
5+
| - type parameter from outer function being used
66
...
77
LL | fn g(&self, x: T) -> T;
88
| - ^ use of generic parameter from outer function
@@ -13,7 +13,7 @@ error[E0401]: can't use generic parameters from outer function
1313
--> $DIR/issue-3021-c.rs:4:30
1414
|
1515
LL | fn siphash<T>() {
16-
| - type parameter from outer function
16+
| - type parameter from outer function being used
1717
...
1818
LL | fn g(&self, x: T) -> T;
1919
| - ^ use of generic parameter from outer function

src/test/ui/issues/issue-3214.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0401]: can't use generic parameters from outer function
22
--> $DIR/issue-3214.rs:3:12
33
|
44
LL | fn foo<T>() {
5-
| --- - type parameter from outer function
5+
| --- - type parameter from outer function being used
66
| |
77
| try adding a local generic parameter in this method instead
88
LL | struct Foo {

src/test/ui/issues/issue-45447.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
trait Foo { const FOO: Self; }
2+
impl Foo for u32 { const FOO: Self = 1; }
3+
fn bar<T: Foo>(n: T) {
4+
const BASE: T = T::FOO;
5+
//~^ ERROR can't use generic parameters in `const` associated item
6+
//~| ERROR can't use generic parameters in `const` associated item
7+
type Type = T;
8+
//~^ ERROR can't use generic parameters in associated type
9+
}
10+
fn main() {}

src/test/ui/issues/issue-45447.stderr

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
error[E0401]: can't use generic parameters in `const` associated item
2+
--> $DIR/issue-45447.rs:4:17
3+
|
4+
LL | fn bar<T: Foo>(n: T) {
5+
| - type parameter being used
6+
LL | const BASE: T = T::FOO;
7+
| ^ use of generic parameter in `const` associated item
8+
|
9+
= help: `const` associated item need a type instead of a generic parameter
10+
11+
error[E0401]: can't use generic parameters in `const` associated item
12+
--> $DIR/issue-45447.rs:4:21
13+
|
14+
LL | fn bar<T: Foo>(n: T) {
15+
| - type parameter being used
16+
LL | const BASE: T = T::FOO;
17+
| ^^^^^^ use of generic parameter in `const` associated item
18+
|
19+
= help: `const` associated item need a type instead of a generic parameter
20+
21+
error[E0401]: can't use generic parameters in associated type
22+
--> $DIR/issue-45447.rs:7:17
23+
|
24+
LL | fn bar<T: Foo>(n: T) {
25+
| - type parameter being used
26+
...
27+
LL | type Type = T;
28+
| ^ use of generic parameter in associated type
29+
|
30+
= help: associated type need a type instead of a generic parameter
31+
32+
error: aborting due to 3 previous errors
33+
34+
For more information about this error, try `rustc --explain E0401`.

src/test/ui/issues/issue-5997-enum.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0401]: can't use generic parameters from outer function
22
--> $DIR/issue-5997-enum.rs:2:16
33
|
44
LL | fn f<Z>() -> bool {
5-
| - - type parameter from outer function
5+
| - - type parameter from outer function being used
66
| |
77
| try adding a local generic parameter in this method instead
88
LL | enum E { V(Z) }

src/test/ui/issues/issue-5997-struct.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0401]: can't use generic parameters from outer function
22
--> $DIR/issue-5997-struct.rs:2:14
33
|
44
LL | fn f<T>() -> bool {
5-
| - - type parameter from outer function
5+
| - - type parameter from outer function being used
66
| |
77
| try adding a local generic parameter in this method instead
88
LL | struct S(T);

src/test/ui/nested-ty-params.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0401]: can't use generic parameters from outer function
22
--> $DIR/nested-ty-params.rs:3:16
33
|
44
LL | fn hd<U>(v: Vec<U> ) -> U {
5-
| - type parameter from outer function
5+
| - type parameter from outer function being used
66
LL | fn hd1(w: [U]) -> U { return w[0]; }
77
| --- ^ use of generic parameter from outer function
88
| |
@@ -12,7 +12,7 @@ error[E0401]: can't use generic parameters from outer function
1212
--> $DIR/nested-ty-params.rs:3:23
1313
|
1414
LL | fn hd<U>(v: Vec<U> ) -> U {
15-
| - type parameter from outer function
15+
| - type parameter from outer function being used
1616
LL | fn hd1(w: [U]) -> U { return w[0]; }
1717
| --- ^ use of generic parameter from outer function
1818
| |

src/test/ui/resolve/resolve-type-param-in-item-in-trait.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0401]: can't use generic parameters from outer function
22
--> $DIR/resolve-type-param-in-item-in-trait.rs:8:22
33
|
44
LL | trait TraitA<A> {
5-
| - type parameter from outer function
5+
| - type parameter from outer function being used
66
LL | fn outer(&self) {
77
| ----- try adding a local generic parameter in this method instead
88
LL | enum Foo<B> {
@@ -13,7 +13,7 @@ error[E0401]: can't use generic parameters from outer function
1313
--> $DIR/resolve-type-param-in-item-in-trait.rs:16:23
1414
|
1515
LL | trait TraitB<A> {
16-
| - type parameter from outer function
16+
| - type parameter from outer function being used
1717
LL | fn outer(&self) {
1818
| ----- try adding a local generic parameter in this method instead
1919
LL | struct Foo<B>(A);
@@ -23,7 +23,7 @@ error[E0401]: can't use generic parameters from outer function
2323
--> $DIR/resolve-type-param-in-item-in-trait.rs:23:28
2424
|
2525
LL | trait TraitC<A> {
26-
| - type parameter from outer function
26+
| - type parameter from outer function being used
2727
LL | fn outer(&self) {
2828
| ----- try adding a local generic parameter in this method instead
2929
LL | struct Foo<B> { a: A }
@@ -33,7 +33,7 @@ error[E0401]: can't use generic parameters from outer function
3333
--> $DIR/resolve-type-param-in-item-in-trait.rs:30:22
3434
|
3535
LL | trait TraitD<A> {
36-
| - type parameter from outer function
36+
| - type parameter from outer function being used
3737
LL | fn outer(&self) {
3838
LL | fn foo<B>(a: A) { }
3939
| ------ ^ use of generic parameter from outer function

src/test/ui/type/type-arg-out-of-scope.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0401]: can't use generic parameters from outer function
22
--> $DIR/type-arg-out-of-scope.rs:3:29
33
|
44
LL | fn foo<T>(x: T) {
5-
| - type parameter from outer function
5+
| - type parameter from outer function being used
66
LL | fn bar(f: Box<dyn FnMut(T) -> T>) { }
77
| --- ^ use of generic parameter from outer function
88
| |
@@ -12,7 +12,7 @@ error[E0401]: can't use generic parameters from outer function
1212
--> $DIR/type-arg-out-of-scope.rs:3:35
1313
|
1414
LL | fn foo<T>(x: T) {
15-
| - type parameter from outer function
15+
| - type parameter from outer function being used
1616
LL | fn bar(f: Box<dyn FnMut(T) -> T>) { }
1717
| --- ^ use of generic parameter from outer function
1818
| |

0 commit comments

Comments
 (0)