Skip to content

Commit c7d3004

Browse files
committed
non_local_defs: point the parent item when appropriate
1 parent 98273ec commit c7d3004

13 files changed

+339
-490
lines changed

compiler/rustc_lint/messages.ftl

+6-5
Original file line numberDiff line numberDiff line change
@@ -543,18 +543,19 @@ lint_non_local_definitions_cargo_update = the {$macro_kind} `{$macro_name}` may
543543
lint_non_local_definitions_deprecation = this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
544544
545545
lint_non_local_definitions_impl = non-local `impl` definition, `impl` blocks should be written at the same level as their item
546-
.move_help =
547-
move this `impl` block outside of the current {$body_kind_descr} {$depth ->
548-
[one] `{$body_name}`
549-
*[other] `{$body_name}` and up {$depth} bodies
550-
}
551546
.remove_help = remove `{$may_remove_part}` to make the `impl` local
552547
.without_trait = methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl`
553548
.with_trait = an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl`
554549
.bounds = `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type
555550
.exception = items in an anonymous const item (`const _: () = {"{"} ... {"}"}`) are treated as in the same scope as the anonymous const's declaration
556551
.const_anon = use a const-anon item to suppress this lint
557552
553+
lint_non_local_definitions_impl_move_help =
554+
move the `impl` block outside of this {$body_kind_descr} {$depth ->
555+
[one] `{$body_name}`
556+
*[other] `{$body_name}` and up {$depth} bodies
557+
}
558+
558559
lint_non_local_definitions_macro_rules = non-local `macro_rules!` definition, `#[macro_export]` macro should be written at top level module
559560
.help =
560561
remove the `#[macro_export]` or move this `macro_rules!` outside the of the current {$body_kind_descr} {$depth ->

compiler/rustc_lint/src/lints.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -1336,8 +1336,7 @@ pub enum NonLocalDefinitionsDiag {
13361336
body_name: String,
13371337
cargo_update: Option<NonLocalDefinitionsCargoUpdateNote>,
13381338
const_anon: Option<Option<Span>>,
1339-
move_help: Span,
1340-
may_move: Vec<Span>,
1339+
move_to: Option<(Span, Vec<Span>)>,
13411340
may_remove: Option<(Span, String)>,
13421341
has_trait: bool,
13431342
self_ty_str: String,
@@ -1362,8 +1361,7 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag {
13621361
body_name,
13631362
cargo_update,
13641363
const_anon,
1365-
move_help,
1366-
may_move,
1364+
move_to,
13671365
may_remove,
13681366
has_trait,
13691367
self_ty_str,
@@ -1385,11 +1383,13 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag {
13851383
diag.note(fluent::lint_without_trait);
13861384
}
13871385

1388-
let mut ms = MultiSpan::from_span(move_help);
1389-
for sp in may_move {
1390-
ms.push_span_label(sp, fluent::lint_non_local_definitions_may_move);
1386+
if let Some((move_help, may_move)) = move_to {
1387+
let mut ms = MultiSpan::from_span(move_help);
1388+
for sp in may_move {
1389+
ms.push_span_label(sp, fluent::lint_non_local_definitions_may_move);
1390+
}
1391+
diag.span_help(ms, fluent::lint_non_local_definitions_impl_move_help);
13911392
}
1392-
diag.span_help(ms, fluent::lint_move_help);
13931393

13941394
if let Some((span, part)) = may_remove {
13951395
diag.arg("may_remove_part", part);

compiler/rustc_lint/src/non_local_def.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -198,17 +198,21 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
198198
}
199199
collector.visit_generics(&impl_.generics);
200200

201-
let may_move: Vec<Span> = collector
201+
let mut may_move: Vec<Span> = collector
202202
.paths
203203
.into_iter()
204204
.filter_map(|path| {
205-
if path_has_local_parent(&path, cx, parent, parent_parent) {
206-
Some(path_span_without_args(&path))
205+
if let Some(did) = path.res.opt_def_id()
206+
&& did_has_local_parent(did, cx.tcx, parent, parent_parent)
207+
{
208+
Some(cx.tcx.def_span(did))
207209
} else {
208210
None
209211
}
210212
})
211213
.collect();
214+
may_move.sort();
215+
may_move.dedup();
212216

213217
let const_anon = matches!(parent_def_kind, DefKind::Const | DefKind::Static { .. })
214218
.then_some(span_for_const_anon_suggestion);
@@ -244,13 +248,21 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
244248
} else {
245249
None
246250
};
251+
let move_to = if may_move.is_empty() {
252+
ms.push_span_label(
253+
cx.tcx.def_span(parent),
254+
fluent::lint_non_local_definitions_impl_move_help,
255+
);
256+
None
257+
} else {
258+
Some((cx.tcx.def_span(parent), may_move))
259+
};
247260

248261
cx.emit_span_lint(
249262
NON_LOCAL_DEFINITIONS,
250263
ms,
251264
NonLocalDefinitionsDiag::Impl {
252265
depth: self.body_depth,
253-
move_help: item.span,
254266
body_kind_descr: cx.tcx.def_kind_descr(parent_def_kind, parent),
255267
body_name: parent_opt_item_name
256268
.map(|s| s.to_ident_string())
@@ -259,7 +271,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
259271
const_anon,
260272
self_ty_str,
261273
of_trait_str,
262-
may_move,
274+
move_to,
263275
may_remove,
264276
has_trait: impl_.of_trait.is_some(),
265277
},

tests/ui/lint/non-local-defs/cargo-update.stderr

+1-5
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,10 @@ LL | non_local_macro::non_local_impl!(LocalStruct);
66
| |
77
| `LocalStruct` is not local
88
| `Debug` is not local
9+
| move the `impl` block outside of this constant `_IMPL_DEBUG`
910
|
1011
= note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type
1112
= note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl`
12-
help: move this `impl` block outside of the current constant `_IMPL_DEBUG`
13-
--> $DIR/cargo-update.rs:17:1
14-
|
15-
LL | non_local_macro::non_local_impl!(LocalStruct);
16-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1713
= note: the macro `non_local_macro::non_local_impl` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro`
1814
= note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration
1915
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>

tests/ui/lint/non-local-defs/consts.stderr

+37-59
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ warning: non-local `impl` definition, `impl` blocks should be written at the sam
22
--> $DIR/consts.rs:13:5
33
|
44
LL | const Z: () = {
5-
| - help: use a const-anon item to suppress this lint: `_`
5+
| -----------
6+
| | |
7+
| | help: use a const-anon item to suppress this lint: `_`
8+
| move the `impl` block outside of this constant `Z`
69
...
710
LL | impl Uto for &Test {}
811
| ^^^^^---^^^^^-----
@@ -12,18 +15,15 @@ LL | impl Uto for &Test {}
1215
|
1316
= note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type
1417
= note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl`
15-
help: move this `impl` block outside of the current constant `Z`
16-
--> $DIR/consts.rs:13:5
17-
|
18-
LL | impl Uto for &Test {}
19-
| ^^^^^^^^^^^^^^^^^^^^^
2018
= note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration
2119
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
2220
= note: `#[warn(non_local_definitions)]` on by default
2321

2422
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
2523
--> $DIR/consts.rs:24:5
2624
|
25+
LL | static A: u32 = {
26+
| ------------- move the `impl` block outside of this static `A`
2727
LL | impl Uto2 for Test {}
2828
| ^^^^^----^^^^^----
2929
| | |
@@ -32,17 +32,14 @@ LL | impl Uto2 for Test {}
3232
|
3333
= note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type
3434
= note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl`
35-
help: move this `impl` block outside of the current static `A`
36-
--> $DIR/consts.rs:24:5
37-
|
38-
LL | impl Uto2 for Test {}
39-
| ^^^^^^^^^^^^^^^^^^^^^
4035
= note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration
4136
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
4237

4338
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
4439
--> $DIR/consts.rs:32:5
4540
|
41+
LL | const B: u32 = {
42+
| ------------ move the `impl` block outside of this constant `B`
4643
LL | impl Uto3 for Test {}
4744
| ^^^^^----^^^^^----
4845
| | |
@@ -51,75 +48,60 @@ LL | impl Uto3 for Test {}
5148
|
5249
= note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type
5350
= note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl`
54-
help: move this `impl` block outside of the current constant `B`
55-
--> $DIR/consts.rs:32:5
56-
|
57-
LL | impl Uto3 for Test {}
58-
| ^^^^^^^^^^^^^^^^^^^^^
5951
= note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration
6052
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
6153

6254
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
6355
--> $DIR/consts.rs:43:5
6456
|
57+
LL | fn main() {
58+
| --------- move the `impl` block outside of this function `main`
6559
LL | impl Test {
6660
| ^^^^^----
6761
| |
6862
| `Test` is not local
6963
|
7064
= note: methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl`
71-
help: move this `impl` block outside of the current function `main`
72-
--> $DIR/consts.rs:43:5
73-
|
74-
LL | / impl Test {
75-
LL | |
76-
LL | | fn foo() {}
77-
LL | | }
78-
| |_____^
7965
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
8066

8167
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
8268
--> $DIR/consts.rs:50:9
8369
|
84-
LL | impl Test {
85-
| ^^^^^----
86-
| |
87-
| `Test` is not local
88-
|
89-
= note: methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl`
90-
help: move this `impl` block outside of the current inline constant `<unnameable>` and up 2 bodies
91-
--> $DIR/consts.rs:50:9
92-
|
93-
LL | / impl Test {
70+
LL | const {
71+
| ___________-
72+
LL | | impl Test {
73+
| | ^^^^^----
74+
| | |
75+
| | `Test` is not local
9476
LL | |
9577
LL | | fn hoo() {}
96-
LL | | }
97-
| |_________^
78+
... |
79+
LL | | 1
80+
LL | | };
81+
| |_____- move the `impl` block outside of this inline constant `<unnameable>` and up 2 bodies
82+
|
83+
= note: methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl`
9884
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
9985

10086
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
10187
--> $DIR/consts.rs:59:9
10288
|
89+
LL | const _: u32 = {
90+
| ------------ move the `impl` block outside of this constant `_` and up 2 bodies
10391
LL | impl Test {
10492
| ^^^^^----
10593
| |
10694
| `Test` is not local
10795
|
10896
= note: methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl`
109-
help: move this `impl` block outside of the current constant `_` and up 2 bodies
110-
--> $DIR/consts.rs:59:9
111-
|
112-
LL | / impl Test {
113-
LL | |
114-
LL | | fn foo2() {}
115-
LL | | }
116-
| |_________^
11797
= note: items in an anonymous const item (`const _: () = { ... }`) are treated as in the same scope as the anonymous const's declaration
11898
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
11999

120100
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
121101
--> $DIR/consts.rs:72:9
122102
|
103+
LL | let _a = || {
104+
| -- move the `impl` block outside of this closure `<unnameable>` and up 2 bodies
123105
LL | impl Uto9 for Test {}
124106
| ^^^^^----^^^^^----
125107
| | |
@@ -128,29 +110,25 @@ LL | impl Uto9 for Test {}
128110
|
129111
= note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type
130112
= note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl`
131-
help: move this `impl` block outside of the current closure `<unnameable>` and up 2 bodies
132-
--> $DIR/consts.rs:72:9
133-
|
134-
LL | impl Uto9 for Test {}
135-
| ^^^^^^^^^^^^^^^^^^^^^
136113
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
137114

138115
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
139116
--> $DIR/consts.rs:79:9
140117
|
141-
LL | impl Uto10 for Test {}
142-
| ^^^^^-----^^^^^----
143-
| | |
144-
| | `Test` is not local
145-
| `Uto10` is not local
118+
LL | type A = [u32; {
119+
| ____________________-
120+
LL | | impl Uto10 for Test {}
121+
| | ^^^^^-----^^^^^----
122+
| | | |
123+
| | | `Test` is not local
124+
| | `Uto10` is not local
125+
LL | |
126+
... |
127+
LL | | }];
128+
| |_____- move the `impl` block outside of this constant expression `<unnameable>` and up 2 bodies
146129
|
147130
= note: `impl` may be usable in bounds, etc. from outside the expression, which might e.g. make something constructible that previously wasn't, because it's still on a publicly-visible type
148131
= note: an `impl` is never scoped, even when it is nested inside an item, as it may impact type checking outside of that item, which can be the case if neither the trait or the self type are at the same nesting level as the `impl`
149-
help: move this `impl` block outside of the current constant expression `<unnameable>` and up 2 bodies
150-
--> $DIR/consts.rs:79:9
151-
|
152-
LL | impl Uto10 for Test {}
153-
| ^^^^^^^^^^^^^^^^^^^^^^
154132
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
155133

156134
warning: 8 warnings emitted

0 commit comments

Comments
 (0)