Skip to content

Commit 98273ec

Browse files
committed
non_local_defs: point to Self and Trait to give more context
1 parent b719529 commit 98273ec

15 files changed

+311
-69
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -4062,6 +4062,7 @@ dependencies = [
40624062
"rustc_feature",
40634063
"rustc_fluent_macro",
40644064
"rustc_hir",
4065+
"rustc_hir_pretty",
40654066
"rustc_index",
40664067
"rustc_infer",
40674068
"rustc_macros",

compiler/rustc_lint/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ rustc_errors = { path = "../rustc_errors" }
1313
rustc_feature = { path = "../rustc_feature" }
1414
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
1515
rustc_hir = { path = "../rustc_hir" }
16+
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
1617
rustc_index = { path = "../rustc_index" }
1718
rustc_infer = { path = "../rustc_infer" }
1819
rustc_macros = { path = "../rustc_macros" }

compiler/rustc_lint/messages.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,10 @@ lint_non_local_definitions_macro_rules = non-local `macro_rules!` definition, `#
567567
568568
lint_non_local_definitions_may_move = may need to be moved as well
569569
570+
lint_non_local_definitions_of_trait_not_local = `{$of_trait_str}` is not local
571+
572+
lint_non_local_definitions_self_ty_not_local = `{$self_ty_str}` is not local
573+
570574
lint_non_snake_case = {$sort} `{$name}` should have a snake case name
571575
.rename_or_convert_suggestion = rename the identifier or convert it to a snake case raw identifier
572576
.cannot_convert_note = `{$sc}` cannot be used as a raw identifier

compiler/rustc_lint/src/lints.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1340,6 +1340,8 @@ pub enum NonLocalDefinitionsDiag {
13401340
may_move: Vec<Span>,
13411341
may_remove: Option<(Span, String)>,
13421342
has_trait: bool,
1343+
self_ty_str: String,
1344+
of_trait_str: Option<String>,
13431345
},
13441346
MacroRules {
13451347
depth: u32,
@@ -1364,11 +1366,17 @@ impl<'a> LintDiagnostic<'a, ()> for NonLocalDefinitionsDiag {
13641366
may_move,
13651367
may_remove,
13661368
has_trait,
1369+
self_ty_str,
1370+
of_trait_str,
13671371
} => {
13681372
diag.primary_message(fluent::lint_non_local_definitions_impl);
13691373
diag.arg("depth", depth);
13701374
diag.arg("body_kind_descr", body_kind_descr);
13711375
diag.arg("body_name", body_name);
1376+
diag.arg("self_ty_str", self_ty_str);
1377+
if let Some(of_trait_str) = of_trait_str {
1378+
diag.arg("of_trait_str", of_trait_str);
1379+
}
13721380

13731381
if has_trait {
13741382
diag.note(fluent::lint_bounds);

compiler/rustc_lint/src/non_local_def.rs

+76-7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use rustc_errors::MultiSpan;
12
use rustc_hir::intravisit::{self, Visitor};
23
use rustc_hir::HirId;
34
use rustc_hir::{def::DefKind, Body, Item, ItemKind, Node, TyKind};
@@ -9,12 +10,13 @@ use rustc_middle::ty::{EarlyBinder, TraitRef, TypeSuperFoldable};
910
use rustc_session::{declare_lint, impl_lint_pass};
1011
use rustc_span::def_id::{DefId, LOCAL_CRATE};
1112
use rustc_span::Span;
12-
use rustc_span::{sym, symbol::kw, ExpnKind, MacroKind};
13+
use rustc_span::{sym, symbol::kw, ExpnKind, MacroKind, Symbol};
1314
use rustc_trait_selection::infer::TyCtxtInferExt;
1415
use rustc_trait_selection::traits::error_reporting::ambiguity::{
1516
compute_applicable_impls_for_diagnostics, CandidateSource,
1617
};
1718

19+
use crate::fluent_generated as fluent;
1820
use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag};
1921
use crate::{LateContext, LateLintPass, LintContext};
2022

@@ -201,11 +203,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
201203
.into_iter()
202204
.filter_map(|path| {
203205
if path_has_local_parent(&path, cx, parent, parent_parent) {
204-
if let Some(args) = &path.segments.last().unwrap().args {
205-
Some(path.span.until(args.span_ext))
206-
} else {
207-
Some(path.span)
208-
}
206+
Some(path_span_without_args(&path))
209207
} else {
210208
None
211209
}
@@ -227,9 +225,29 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
227225
_ => None,
228226
};
229227

228+
let impl_span = item.span.shrink_to_lo().to(impl_.self_ty.span);
229+
let mut ms = MultiSpan::from_span(impl_span);
230+
231+
let (self_ty_span, self_ty_str) =
232+
self_ty_kind_for_diagnostic(&impl_.self_ty, cx.tcx);
233+
234+
ms.push_span_label(
235+
self_ty_span,
236+
fluent::lint_non_local_definitions_self_ty_not_local,
237+
);
238+
let of_trait_str = if let Some(of_trait) = &impl_.of_trait {
239+
ms.push_span_label(
240+
path_span_without_args(&of_trait.path),
241+
fluent::lint_non_local_definitions_of_trait_not_local,
242+
);
243+
Some(path_name_to_string(&of_trait.path))
244+
} else {
245+
None
246+
};
247+
230248
cx.emit_span_lint(
231249
NON_LOCAL_DEFINITIONS,
232-
item.span.shrink_to_lo().to(impl_.self_ty.span),
250+
ms,
233251
NonLocalDefinitionsDiag::Impl {
234252
depth: self.body_depth,
235253
move_help: item.span,
@@ -239,6 +257,8 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
239257
.unwrap_or_else(|| "<unnameable>".to_string()),
240258
cargo_update: cargo_update(),
241259
const_anon,
260+
self_ty_str,
261+
of_trait_str,
242262
may_move,
243263
may_remove,
244264
has_trait: impl_.of_trait.is_some(),
@@ -447,3 +467,52 @@ fn did_has_local_parent(
447467
false
448468
}
449469
}
470+
471+
/// Return for a given `Path` the span until the last args
472+
fn path_span_without_args(path: &Path<'_>) -> Span {
473+
if let Some(args) = &path.segments.last().unwrap().args {
474+
path.span.until(args.span_ext)
475+
} else {
476+
path.span
477+
}
478+
}
479+
480+
/// Return a "error message-able" ident for the last segment of the `Path`
481+
fn path_name_to_string(path: &Path<'_>) -> String {
482+
path.segments.last().unwrap().ident.name.to_ident_string()
483+
}
484+
485+
/// Compute the `Span` and visual representation for the `Self` we want to point at;
486+
/// It follows part of the actual logic of non-local, and if possible return the least
487+
/// amount possible for the span and representation.
488+
fn self_ty_kind_for_diagnostic(ty: &rustc_hir::Ty<'_>, tcx: TyCtxt<'_>) -> (Span, String) {
489+
match ty.kind {
490+
TyKind::Path(QPath::Resolved(_, ty_path)) => (
491+
path_span_without_args(ty_path),
492+
ty_path
493+
.res
494+
.opt_def_id()
495+
.map(|did| tcx.opt_item_name(did))
496+
.flatten()
497+
.as_ref()
498+
.map(|s| Symbol::as_str(s))
499+
.unwrap_or("<unnameable>")
500+
.to_string(),
501+
),
502+
TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => {
503+
let path = &principle_poly_trait_ref.trait_ref.path;
504+
(
505+
path_span_without_args(path),
506+
path.res
507+
.opt_def_id()
508+
.map(|did| tcx.opt_item_name(did))
509+
.flatten()
510+
.as_ref()
511+
.map(|s| Symbol::as_str(s))
512+
.unwrap_or("<unnameable>")
513+
.to_string(),
514+
)
515+
}
516+
_ => (ty.span, rustc_hir_pretty::ty_to_string(&tcx, ty)),
517+
}
518+
}

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

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ warning: non-local `impl` definition, `impl` blocks should be written at the sam
33
|
44
LL | non_local_macro::non_local_impl!(LocalStruct);
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
| |
7+
| `LocalStruct` is not local
8+
| `Debug` is not local
69
|
710
= 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
811
= 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`

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

+29-8
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ LL | const Z: () = {
55
| - help: use a const-anon item to suppress this lint: `_`
66
...
77
LL | impl Uto for &Test {}
8-
| ^^^^^^^^^^^^^^^^^^
8+
| ^^^^^---^^^^^-----
9+
| | |
10+
| | `&'_ Test` is not local
11+
| `Uto` is not local
912
|
1013
= 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
1114
= 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`
@@ -22,7 +25,10 @@ warning: non-local `impl` definition, `impl` blocks should be written at the sam
2225
--> $DIR/consts.rs:24:5
2326
|
2427
LL | impl Uto2 for Test {}
25-
| ^^^^^^^^^^^^^^^^^^
28+
| ^^^^^----^^^^^----
29+
| | |
30+
| | `Test` is not local
31+
| `Uto2` is not local
2632
|
2733
= 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
2834
= 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`
@@ -38,7 +44,10 @@ warning: non-local `impl` definition, `impl` blocks should be written at the sam
3844
--> $DIR/consts.rs:32:5
3945
|
4046
LL | impl Uto3 for Test {}
41-
| ^^^^^^^^^^^^^^^^^^
47+
| ^^^^^----^^^^^----
48+
| | |
49+
| | `Test` is not local
50+
| `Uto3` is not local
4251
|
4352
= 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
4453
= 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,7 +63,9 @@ warning: non-local `impl` definition, `impl` blocks should be written at the sam
5463
--> $DIR/consts.rs:43:5
5564
|
5665
LL | impl Test {
57-
| ^^^^^^^^^
66+
| ^^^^^----
67+
| |
68+
| `Test` is not local
5869
|
5970
= 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`
6071
help: move this `impl` block outside of the current function `main`
@@ -71,7 +82,9 @@ warning: non-local `impl` definition, `impl` blocks should be written at the sam
7182
--> $DIR/consts.rs:50:9
7283
|
7384
LL | impl Test {
74-
| ^^^^^^^^^
85+
| ^^^^^----
86+
| |
87+
| `Test` is not local
7588
|
7689
= 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`
7790
help: move this `impl` block outside of the current inline constant `<unnameable>` and up 2 bodies
@@ -88,7 +101,9 @@ warning: non-local `impl` definition, `impl` blocks should be written at the sam
88101
--> $DIR/consts.rs:59:9
89102
|
90103
LL | impl Test {
91-
| ^^^^^^^^^
104+
| ^^^^^----
105+
| |
106+
| `Test` is not local
92107
|
93108
= 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`
94109
help: move this `impl` block outside of the current constant `_` and up 2 bodies
@@ -106,7 +121,10 @@ warning: non-local `impl` definition, `impl` blocks should be written at the sam
106121
--> $DIR/consts.rs:72:9
107122
|
108123
LL | impl Uto9 for Test {}
109-
| ^^^^^^^^^^^^^^^^^^
124+
| ^^^^^----^^^^^----
125+
| | |
126+
| | `Test` is not local
127+
| `Uto9` is not local
110128
|
111129
= 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
112130
= 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`
@@ -121,7 +139,10 @@ warning: non-local `impl` definition, `impl` blocks should be written at the sam
121139
--> $DIR/consts.rs:79:9
122140
|
123141
LL | impl Uto10 for Test {}
124-
| ^^^^^^^^^^^^^^^^^^^
142+
| ^^^^^-----^^^^^----
143+
| | |
144+
| | `Test` is not local
145+
| `Uto10` is not local
125146
|
126147
= 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
127148
= 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`

tests/ui/lint/non-local-defs/exhaustive-trait.stderr

+24-6
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/exhaustive-trait.rs:7:5
33
|
44
LL | impl PartialEq<()> for Dog {
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
5+
| ^^^^^---------^^^^^^^^^---
6+
| | |
7+
| | `Dog` is not local
8+
| `PartialEq` is not local
69
|
710
= 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
811
= 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`
@@ -23,7 +26,10 @@ warning: non-local `impl` definition, `impl` blocks should be written at the sam
2326
--> $DIR/exhaustive-trait.rs:14:5
2427
|
2528
LL | impl PartialEq<()> for &Dog {
26-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
29+
| ^^^^^---------^^^^^^^^^----
30+
| | |
31+
| | `&'_ Dog` is not local
32+
| `PartialEq` is not local
2733
|
2834
= 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
2935
= 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`
@@ -43,7 +49,10 @@ warning: non-local `impl` definition, `impl` blocks should be written at the sam
4349
--> $DIR/exhaustive-trait.rs:21:5
4450
|
4551
LL | impl PartialEq<Dog> for () {
46-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
52+
| ^^^^^---------^^^^^^^^^^--
53+
| | |
54+
| | `()` is not local
55+
| `PartialEq` is not local
4756
|
4857
= 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
4958
= 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`
@@ -63,7 +72,10 @@ warning: non-local `impl` definition, `impl` blocks should be written at the sam
6372
--> $DIR/exhaustive-trait.rs:28:5
6473
|
6574
LL | impl PartialEq<&Dog> for () {
66-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
75+
| ^^^^^---------^^^^^^^^^^^--
76+
| | |
77+
| | `()` is not local
78+
| `PartialEq` is not local
6779
|
6880
= 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
6981
= 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`
@@ -83,7 +95,10 @@ warning: non-local `impl` definition, `impl` blocks should be written at the sam
8395
--> $DIR/exhaustive-trait.rs:35:5
8496
|
8597
LL | impl PartialEq<Dog> for &Dog {
86-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
98+
| ^^^^^---------^^^^^^^^^^----
99+
| | |
100+
| | `&'_ Dog` is not local
101+
| `PartialEq` is not local
87102
|
88103
= 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
89104
= 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`
@@ -103,7 +118,10 @@ warning: non-local `impl` definition, `impl` blocks should be written at the sam
103118
--> $DIR/exhaustive-trait.rs:42:5
104119
|
105120
LL | impl PartialEq<&Dog> for &Dog {
106-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
121+
| ^^^^^---------^^^^^^^^^^^----
122+
| | |
123+
| | `&'_ Dog` is not local
124+
| `PartialEq` is not local
107125
|
108126
= 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
109127
= 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`

0 commit comments

Comments
 (0)