Rework non_local_definitions lint to only be a syntactic heuristic

This commit is contained in:
Urgau 2024-07-09 18:33:37 +02:00
parent cb58668748
commit 00a6ebfbf5
13 changed files with 36 additions and 643 deletions

View File

@ -592,7 +592,6 @@ lint_non_local_definitions_cargo_update = the {$macro_kind} `{$macro_name}` may
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> 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>
lint_non_local_definitions_impl = non-local `impl` definition, `impl` blocks should be written at the same level as their item lint_non_local_definitions_impl = non-local `impl` definition, `impl` blocks should be written at the same level as their item
.remove_help = remove `{$may_remove_part}` to make the `impl` local
.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` .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`
.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` .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`
.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 .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
@ -617,8 +616,6 @@ lint_non_local_definitions_macro_rules = non-local `macro_rules!` definition, `#
remove the `#[macro_export]` or make this doc-test a standalone test with its own `fn main() {"{"} ... {"}"}` remove the `#[macro_export]` or make this doc-test a standalone test with its own `fn main() {"{"} ... {"}"}`
.non_local = a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute .non_local = a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute
lint_non_local_definitions_may_move = may need to be moved as well
lint_non_local_definitions_of_trait_not_local = `{$of_trait_str}` is not local lint_non_local_definitions_of_trait_not_local = `{$of_trait_str}` is not local
lint_non_local_definitions_self_ty_not_local = `{$self_ty_str}` is not local lint_non_local_definitions_self_ty_not_local = `{$self_ty_str}` is not local

View File

@ -1375,9 +1375,7 @@ pub(crate) enum NonLocalDefinitionsDiag {
body_name: String, body_name: String,
cargo_update: Option<NonLocalDefinitionsCargoUpdateNote>, cargo_update: Option<NonLocalDefinitionsCargoUpdateNote>,
const_anon: Option<Option<Span>>, const_anon: Option<Option<Span>>,
move_to: Option<(Span, Vec<Span>)>,
doctest: bool, doctest: bool,
may_remove: Option<(Span, String)>,
has_trait: bool, has_trait: bool,
self_ty_str: String, self_ty_str: String,
of_trait_str: Option<String>, of_trait_str: Option<String>,
@ -1401,9 +1399,7 @@ fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
body_name, body_name,
cargo_update, cargo_update,
const_anon, const_anon,
move_to,
doctest, doctest,
may_remove,
has_trait, has_trait,
self_ty_str, self_ty_str,
of_trait_str, of_trait_str,
@ -1434,27 +1430,10 @@ fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) {
diag.note(fluent::lint_without_trait); diag.note(fluent::lint_without_trait);
} }
if let Some((move_help, may_move)) = move_to {
let mut ms = MultiSpan::from_span(move_help);
for sp in may_move {
ms.push_span_label(sp, fluent::lint_non_local_definitions_may_move);
}
diag.span_help(ms, fluent::lint_non_local_definitions_impl_move_help);
}
if doctest { if doctest {
diag.help(fluent::lint_doctest); diag.help(fluent::lint_doctest);
} }
if let Some((span, part)) = may_remove {
diag.arg("may_remove_part", part);
diag.span_suggestion(
span,
fluent::lint_remove_help,
"",
Applicability::MaybeIncorrect,
);
}
if let Some(const_anon) = const_anon { if let Some(const_anon) = const_anon {
diag.note(fluent::lint_exception); diag.note(fluent::lint_exception);
if let Some(const_anon) = const_anon { if let Some(const_anon) = const_anon {

View File

@ -2,19 +2,11 @@
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Body, HirId, Item, ItemKind, Node, Path, QPath, TyKind}; use rustc_hir::{Body, HirId, Item, ItemKind, Node, Path, QPath, TyKind};
use rustc_infer::infer::InferCtxt; use rustc_middle::ty::TyCtxt;
use rustc_infer::traits::{Obligation, ObligationCause};
use rustc_middle::ty::{
self, Binder, EarlyBinder, TraitRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
};
use rustc_session::{declare_lint, impl_lint_pass}; use rustc_session::{declare_lint, impl_lint_pass};
use rustc_span::def_id::{DefId, LOCAL_CRATE}; use rustc_span::def_id::{DefId, LOCAL_CRATE};
use rustc_span::symbol::kw; use rustc_span::symbol::kw;
use rustc_span::{ExpnKind, MacroKind, Span, Symbol, sym}; use rustc_span::{ExpnKind, MacroKind, Span, Symbol, sym, sym};
use rustc_trait_selection::error_reporting::traits::ambiguity::{
CandidateSource, compute_applicable_impls_for_diagnostics,
};
use rustc_trait_selection::infer::TyCtxtInferExt;
use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag}; use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag};
use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent}; use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
@ -142,42 +134,22 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
None None
}; };
// Part 1: Is the Self type local? // 1. We collect all the `hir::Path` from the `Self` type and `Trait` ref
let self_ty_has_local_parent = // of the `impl` definition
ty_has_local_parent(&impl_.self_ty.kind, cx, parent, parent_parent); let mut collector = PathCollector { paths: Vec::new() };
collector.visit_ty(&impl_.self_ty);
if self_ty_has_local_parent { if let Some(of_trait) = &impl_.of_trait {
return; collector.visit_trait_ref(of_trait);
} }
// Part 2: Is the Trait local? // 2. We check if any of path reference a "local" parent and if that the case
let of_trait_has_local_parent = impl_ // we bail out as asked by T-lang, even though this isn't correct from a
.of_trait // type-system point of view, as inference exists and could still leak the impl.
.map(|of_trait| path_has_local_parent(of_trait.path, cx, parent, parent_parent)) if collector
.unwrap_or(false); .paths
.iter()
if of_trait_has_local_parent { .any(|path| path_has_local_parent(path, cx, parent, parent_parent))
return; {
}
// Part 3: Is the impl definition leaking outside it's defining scope?
//
// We always consider inherent impls to be leaking.
let impl_has_enough_non_local_candidates = cx
.tcx
.impl_trait_ref(def_id)
.map(|binder| {
impl_trait_ref_has_enough_non_local_candidates(
cx.tcx,
item.span,
def_id,
binder,
|did| did_has_local_parent(did, cx.tcx, parent, parent_parent),
)
})
.unwrap_or(false);
if impl_has_enough_non_local_candidates {
return; return;
} }
@ -199,18 +171,6 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
let const_anon = matches!(parent_def_kind, DefKind::Const | DefKind::Static { .. }) let const_anon = matches!(parent_def_kind, DefKind::Const | DefKind::Static { .. })
.then_some(span_for_const_anon_suggestion); .then_some(span_for_const_anon_suggestion);
let may_remove = match &impl_.self_ty.kind {
TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty)
if ty_has_local_parent(&mut_ty.ty.kind, cx, parent, parent_parent) =>
{
let type_ =
if matches!(impl_.self_ty.kind, TyKind::Ptr(_)) { "*" } else { "&" };
let part = format!("{}{}", type_, mut_ty.mutbl.prefix_str());
Some((impl_.self_ty.span.shrink_to_lo().until(mut_ty.ty.span), part))
}
_ => None,
};
let impl_span = item.span.shrink_to_lo().to(impl_.self_ty.span); let impl_span = item.span.shrink_to_lo().to(impl_.self_ty.span);
let mut ms = MultiSpan::from_span(impl_span); let mut ms = MultiSpan::from_span(impl_span);
@ -221,6 +181,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
self_ty_span, self_ty_span,
fluent::lint_non_local_definitions_self_ty_not_local, fluent::lint_non_local_definitions_self_ty_not_local,
); );
let of_trait_str = if let Some(of_trait) = &impl_.of_trait { let of_trait_str = if let Some(of_trait) = &impl_.of_trait {
ms.push_span_label( ms.push_span_label(
path_span_without_args(&of_trait.path), path_span_without_args(&of_trait.path),
@ -231,44 +192,14 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
None None
}; };
let (doctest, move_to) = if is_at_toplevel_doctest() { let doctest = is_at_toplevel_doctest();
(true, None)
} else {
let mut collector = PathCollector { paths: Vec::new() };
collector.visit_ty(&impl_.self_ty);
if let Some(of_trait) = &impl_.of_trait {
collector.visit_trait_ref(of_trait);
}
collector.visit_generics(&impl_.generics);
let mut may_move: Vec<Span> = collector if !doctest {
.paths ms.push_span_label(
.into_iter() cx.tcx.def_span(parent),
.filter_map(|path| { fluent::lint_non_local_definitions_impl_move_help,
if let Some(did) = path.res.opt_def_id() );
&& did_has_local_parent(did, cx.tcx, parent, parent_parent) }
{
Some(cx.tcx.def_span(did))
} else {
None
}
})
.collect();
may_move.sort();
may_move.dedup();
let move_to = if may_move.is_empty() {
ms.push_span_label(
cx.tcx.def_span(parent),
fluent::lint_non_local_definitions_impl_move_help,
);
None
} else {
Some((cx.tcx.def_span(parent), may_move))
};
(false, move_to)
};
let macro_to_change = let macro_to_change =
if let ExpnKind::Macro(kind, name) = item.span.ctxt().outer_expn_data().kind { if let ExpnKind::Macro(kind, name) = item.span.ctxt().outer_expn_data().kind {
@ -287,9 +218,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
const_anon, const_anon,
self_ty_str, self_ty_str,
of_trait_str, of_trait_str,
move_to,
doctest, doctest,
may_remove,
has_trait: impl_.of_trait.is_some(), has_trait: impl_.of_trait.is_some(),
macro_to_change, macro_to_change,
}) })
@ -316,90 +245,6 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
} }
} }
// Detecting if the impl definition is leaking outside of its defining scope.
//
// Rule: for each impl, instantiate all local types with inference vars and
// then assemble candidates for that goal, if there are more than 1 (non-private
// impls), it does not leak.
//
// https://github.com/rust-lang/rust/issues/121621#issuecomment-1976826895
fn impl_trait_ref_has_enough_non_local_candidates<'tcx>(
tcx: TyCtxt<'tcx>,
infer_span: Span,
trait_def_id: DefId,
binder: EarlyBinder<'tcx, TraitRef<'tcx>>,
mut did_has_local_parent: impl FnMut(DefId) -> bool,
) -> bool {
let infcx = tcx
.infer_ctxt()
// We use the new trait solver since the obligation we are trying to
// prove here may overflow and those are fatal in the old trait solver.
// Which is unacceptable for a lint.
//
// Thanksfully the part we use here are very similar to the
// new-trait-solver-as-coherence, which is in stabilization.
//
// https://github.com/rust-lang/rust/issues/123573
.with_next_trait_solver(true)
.build();
let trait_ref = binder.instantiate(tcx, infcx.fresh_args_for_item(infer_span, trait_def_id));
let trait_ref = trait_ref.fold_with(&mut ReplaceLocalTypesWithInfer {
infcx: &infcx,
infer_span,
did_has_local_parent: &mut did_has_local_parent,
});
let poly_trait_obligation = Obligation::new(
tcx,
ObligationCause::dummy(),
ty::ParamEnv::empty(),
Binder::dummy(trait_ref),
);
let ambiguities = compute_applicable_impls_for_diagnostics(&infcx, &poly_trait_obligation);
let mut it = ambiguities.iter().filter(|ambi| match ambi {
CandidateSource::DefId(did) => !did_has_local_parent(*did),
CandidateSource::ParamEnv(_) => unreachable!(),
});
let _ = it.next();
it.next().is_some()
}
/// Replace every local type by inference variable.
///
/// ```text
/// <Global<Local> as std::cmp::PartialEq<Global<Local>>>
/// to
/// <Global<_> as std::cmp::PartialEq<Global<_>>>
/// ```
struct ReplaceLocalTypesWithInfer<'a, 'tcx, F: FnMut(DefId) -> bool> {
infcx: &'a InferCtxt<'tcx>,
did_has_local_parent: F,
infer_span: Span,
}
impl<'a, 'tcx, F: FnMut(DefId) -> bool> TypeFolder<TyCtxt<'tcx>>
for ReplaceLocalTypesWithInfer<'a, 'tcx, F>
{
fn cx(&self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
if let Some(def) = t.ty_adt_def()
&& (self.did_has_local_parent)(def.did())
{
self.infcx.next_ty_var(self.infer_span)
} else {
t.super_fold_with(self)
}
}
}
/// Simple hir::Path collector /// Simple hir::Path collector
struct PathCollector<'tcx> { struct PathCollector<'tcx> {
paths: Vec<Path<'tcx>>, paths: Vec<Path<'tcx>>,
@ -412,42 +257,6 @@ fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) {
} }
} }
/// Given a `Ty` we check if the (outermost) type is local.
fn ty_has_local_parent(
ty_kind: &TyKind<'_>,
cx: &LateContext<'_>,
impl_parent: DefId,
impl_parent_parent: Option<DefId>,
) -> bool {
match ty_kind {
TyKind::Path(QPath::Resolved(_, ty_path)) => {
path_has_local_parent(ty_path, cx, impl_parent, impl_parent_parent)
}
TyKind::TraitObject([principle_poly_trait_ref, ..], _, _) => path_has_local_parent(
principle_poly_trait_ref.0.trait_ref.path,
cx,
impl_parent,
impl_parent_parent,
),
TyKind::TraitObject([], _, _)
| TyKind::InferDelegation(_, _)
| TyKind::Slice(_)
| TyKind::Array(_, _)
| TyKind::Ptr(_)
| TyKind::Ref(_, _)
| TyKind::BareFn(_)
| TyKind::Never
| TyKind::Tup(_)
| TyKind::Path(_)
| TyKind::Pat(..)
| TyKind::AnonAdt(_)
| TyKind::OpaqueDef(_, _, _)
| TyKind::Typeof(_)
| TyKind::Infer
| TyKind::Err(_) => false,
}
}
/// Given a path and a parent impl def id, this checks if the if parent resolution /// Given a path and a parent impl def id, this checks if the if parent resolution
/// def id correspond to the def id of the parent impl definition. /// def id correspond to the def id of the parent impl definition.
/// ///

View File

@ -55,18 +55,13 @@ impl Trait for Test {}
struct InsideMain; struct InsideMain;
impl Trait for &InsideMain {}
impl Trait for *mut InsideMain {} impl Trait for *mut InsideMain {}
//~^ WARN non-local `impl` definition
impl Trait for *mut [InsideMain] {} impl Trait for *mut [InsideMain] {}
//~^ WARN non-local `impl` definition
impl Trait for [InsideMain; 8] {} impl Trait for [InsideMain; 8] {}
//~^ WARN non-local `impl` definition
impl Trait for (InsideMain,) {} impl Trait for (InsideMain,) {}
//~^ WARN non-local `impl` definition
impl Trait for fn(InsideMain) -> () {} impl Trait for fn(InsideMain) -> () {}
//~^ WARN non-local `impl` definition
impl Trait for fn() -> InsideMain {} impl Trait for fn() -> InsideMain {}
//~^ WARN non-local `impl` definition
fn inside_inside() { fn inside_inside() {
impl Display for InsideMain { impl Display for InsideMain {

View File

@ -186,134 +186,7 @@ LL | impl Trait for Test {}
= 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> = 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>
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
--> $DIR/exhaustive.rs:58:5 --> $DIR/exhaustive.rs:67:9
|
LL | impl Trait for *mut InsideMain {}
| ^^^^^-----^^^^^---------------
| | |
| | `*mut InsideMain` is not local
| | help: remove `*mut ` to make the `impl` local
| `Trait` is not local
|
= 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
= 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`
help: move the `impl` block outside of this function `main`
--> $DIR/exhaustive.rs:9:1
|
LL | fn main() {
| ^^^^^^^^^
...
LL | struct InsideMain;
| ----------------- may need to be moved as well
= 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>
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
--> $DIR/exhaustive.rs:60:5
|
LL | impl Trait for *mut [InsideMain] {}
| ^^^^^-----^^^^^-----------------
| | |
| | `*mut [InsideMain]` is not local
| `Trait` is not local
|
= 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
= 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`
help: move the `impl` block outside of this function `main`
--> $DIR/exhaustive.rs:9:1
|
LL | fn main() {
| ^^^^^^^^^
...
LL | struct InsideMain;
| ----------------- may need to be moved as well
= 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>
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
--> $DIR/exhaustive.rs:62:5
|
LL | impl Trait for [InsideMain; 8] {}
| ^^^^^-----^^^^^---------------
| | |
| | `[InsideMain; 8]` is not local
| `Trait` is not local
|
= 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
= 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`
help: move the `impl` block outside of this function `main`
--> $DIR/exhaustive.rs:9:1
|
LL | fn main() {
| ^^^^^^^^^
...
LL | struct InsideMain;
| ----------------- may need to be moved as well
= 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>
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
--> $DIR/exhaustive.rs:64:5
|
LL | impl Trait for (InsideMain,) {}
| ^^^^^-----^^^^^-------------
| | |
| | `(InsideMain,)` is not local
| `Trait` is not local
|
= 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
= 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`
help: move the `impl` block outside of this function `main`
--> $DIR/exhaustive.rs:9:1
|
LL | fn main() {
| ^^^^^^^^^
...
LL | struct InsideMain;
| ----------------- may need to be moved as well
= 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>
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
--> $DIR/exhaustive.rs:66:5
|
LL | impl Trait for fn(InsideMain) -> () {}
| ^^^^^-----^^^^^--------------------
| | |
| | `fn(: InsideMain) -> ()` is not local
| `Trait` is not local
|
= 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
= 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`
help: move the `impl` block outside of this function `main`
--> $DIR/exhaustive.rs:9:1
|
LL | fn main() {
| ^^^^^^^^^
...
LL | struct InsideMain;
| ----------------- may need to be moved as well
= 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>
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
--> $DIR/exhaustive.rs:68:5
|
LL | impl Trait for fn() -> InsideMain {}
| ^^^^^-----^^^^^------------------
| | |
| | `fn() -> InsideMain` is not local
| `Trait` is not local
|
= 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
= 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`
help: move the `impl` block outside of this function `main`
--> $DIR/exhaustive.rs:9:1
|
LL | fn main() {
| ^^^^^^^^^
...
LL | struct InsideMain;
| ----------------- may need to be moved as well
= 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>
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
--> $DIR/exhaustive.rs:72:9
| |
LL | fn inside_inside() { LL | fn inside_inside() {
| ------------------ move the `impl` block outside of this function `inside_inside` and up 2 bodies | ------------------ move the `impl` block outside of this function `inside_inside` and up 2 bodies
@ -328,7 +201,7 @@ LL | impl Display for InsideMain {
= 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> = 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>
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
--> $DIR/exhaustive.rs:79:9 --> $DIR/exhaustive.rs:74:9
| |
LL | fn inside_inside() { LL | fn inside_inside() {
| ------------------ move the `impl` block outside of this function `inside_inside` and up 2 bodies | ------------------ move the `impl` block outside of this function `inside_inside` and up 2 bodies
@ -341,5 +214,5 @@ LL | impl InsideMain {
= 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` = 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`
= 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> = 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>
warning: 20 warnings emitted warning: 14 warnings emitted

View File

@ -16,7 +16,6 @@ fn from(_: Cat) -> () {
struct Elephant; struct Elephant;
impl From<Wrap<Wrap<Elephant>>> for () { impl From<Wrap<Wrap<Elephant>>> for () {
//~^ WARN non-local `impl` definition
fn from(_: Wrap<Wrap<Elephant>>) -> Self { fn from(_: Wrap<Wrap<Elephant>>) -> Self {
todo!() todo!()
} }
@ -30,7 +29,6 @@ impl StillNonLocal for &str {}
fn only_global() { fn only_global() {
struct Foo; struct Foo;
impl StillNonLocal for &Foo {} impl StillNonLocal for &Foo {}
//~^ WARN non-local `impl` definition
} }
struct GlobalSameFunction; struct GlobalSameFunction;
@ -38,7 +36,6 @@ impl StillNonLocal for &Foo {}
fn same_function() { fn same_function() {
struct Local1(GlobalSameFunction); struct Local1(GlobalSameFunction);
impl From<Local1> for GlobalSameFunction { impl From<Local1> for GlobalSameFunction {
//~^ WARN non-local `impl` definition
fn from(x: Local1) -> GlobalSameFunction { fn from(x: Local1) -> GlobalSameFunction {
x.0 x.0
} }
@ -46,7 +43,6 @@ fn from(x: Local1) -> GlobalSameFunction {
struct Local2(GlobalSameFunction); struct Local2(GlobalSameFunction);
impl From<Local2> for GlobalSameFunction { impl From<Local2> for GlobalSameFunction {
//~^ WARN non-local `impl` definition
fn from(x: Local2) -> GlobalSameFunction { fn from(x: Local2) -> GlobalSameFunction {
x.0 x.0
} }
@ -59,8 +55,6 @@ fn diff_function_1() {
struct Local(GlobalDifferentFunction); struct Local(GlobalDifferentFunction);
impl From<Local> for GlobalDifferentFunction { impl From<Local> for GlobalDifferentFunction {
// FIXME(Urgau): Should warn but doesn't since we currently consider
// the other impl to be "global", but that's not the case for the type-system
fn from(x: Local) -> GlobalDifferentFunction { fn from(x: Local) -> GlobalDifferentFunction {
x.0 x.0
} }
@ -71,8 +65,6 @@ fn diff_function_2() {
struct Local(GlobalDifferentFunction); struct Local(GlobalDifferentFunction);
impl From<Local> for GlobalDifferentFunction { impl From<Local> for GlobalDifferentFunction {
// FIXME(Urgau): Should warn but doesn't since we currently consider
// the other impl to be "global", but that's not the case for the type-system
fn from(x: Local) -> GlobalDifferentFunction { fn from(x: Local) -> GlobalDifferentFunction {
x.0 x.0
} }

View File

@ -14,87 +14,5 @@ LL | impl From<Cat> for () {
= 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> = 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>
= note: `#[warn(non_local_definitions)]` on by default = note: `#[warn(non_local_definitions)]` on by default
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item warning: 1 warning emitted
--> $DIR/from-local-for-global.rs:18:5
|
LL | impl From<Wrap<Wrap<Elephant>>> for () {
| ^^^^^----^^^^^^^^^^^^^^^^^^^^^^^^^^^--
| | |
| `From` is not local `()` is not local
|
= 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
= 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`
help: move the `impl` block outside of this function `main`
--> $DIR/from-local-for-global.rs:7:1
|
LL | fn main() {
| ^^^^^^^^^
...
LL | struct Elephant;
| --------------- may need to be moved as well
= 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>
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
--> $DIR/from-local-for-global.rs:32:5
|
LL | impl StillNonLocal for &Foo {}
| ^^^^^-------------^^^^^----
| | |
| | `&'_ Foo` is not local
| | help: remove `&` to make the `impl` local
| `StillNonLocal` is not local
|
= 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
= 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`
help: move the `impl` block outside of this function `only_global`
--> $DIR/from-local-for-global.rs:30:1
|
LL | fn only_global() {
| ^^^^^^^^^^^^^^^^
LL | struct Foo;
| ---------- may need to be moved as well
= 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>
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
--> $DIR/from-local-for-global.rs:40:5
|
LL | impl From<Local1> for GlobalSameFunction {
| ^^^^^----^^^^^^^^^^^^^------------------
| | |
| | `GlobalSameFunction` is not local
| `From` is not local
|
= 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
= 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`
help: move the `impl` block outside of this function `same_function`
--> $DIR/from-local-for-global.rs:38:1
|
LL | fn same_function() {
| ^^^^^^^^^^^^^^^^^^
LL | struct Local1(GlobalSameFunction);
| ------------- may need to be moved as well
= 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>
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
--> $DIR/from-local-for-global.rs:48:5
|
LL | impl From<Local2> for GlobalSameFunction {
| ^^^^^----^^^^^^^^^^^^^------------------
| | |
| | `GlobalSameFunction` is not local
| `From` is not local
|
= 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
= 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`
help: move the `impl` block outside of this function `same_function`
--> $DIR/from-local-for-global.rs:38:1
|
LL | fn same_function() {
| ^^^^^^^^^^^^^^^^^^
...
LL | struct Local2(GlobalSameFunction);
| ------------- may need to be moved as well
= 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>
warning: 5 warnings emitted

View File

@ -30,7 +30,6 @@ fn fun() {
#[derive(Debug)] #[derive(Debug)]
struct OwO; struct OwO;
impl Default for UwU<OwO> { impl Default for UwU<OwO> {
//~^ WARN non-local `impl` definition
fn default() -> Self { fn default() -> Self {
UwU(OwO) UwU(OwO)
} }
@ -41,7 +40,6 @@ fn meow() {
#[derive(Debug)] #[derive(Debug)]
struct Cat; struct Cat;
impl AsRef<Cat> for () { impl AsRef<Cat> for () {
//~^ WARN non-local `impl` definition
fn as_ref(&self) -> &Cat { &Cat } fn as_ref(&self) -> &Cat { &Cat }
} }
} }
@ -52,7 +50,6 @@ fn fun2() {
#[derive(Debug, Default)] #[derive(Debug, Default)]
struct B; struct B;
impl PartialEq<B> for G { impl PartialEq<B> for G {
//~^ WARN non-local `impl` definition
fn eq(&self, _: &B) -> bool { fn eq(&self, _: &B) -> bool {
true true
} }
@ -67,14 +64,12 @@ fn rawr() {
struct Lion; struct Lion;
impl From<Wrap<Wrap<Lion>>> for () { impl From<Wrap<Wrap<Lion>>> for () {
//~^ WARN non-local `impl` definition
fn from(_: Wrap<Wrap<Lion>>) -> Self { fn from(_: Wrap<Wrap<Lion>>) -> Self {
todo!() todo!()
} }
} }
impl From<()> for Wrap<Lion> { impl From<()> for Wrap<Lion> {
//~^ WARN non-local `impl` definition
fn from(_: ()) -> Self { fn from(_: ()) -> Self {
todo!() todo!()
} }

View File

@ -1,6 +1,9 @@
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
--> $DIR/generics.rs:9:5 --> $DIR/generics.rs:9:5
| |
LL | fn main() {
| --------- move the `impl` block outside of this function `main`
...
LL | impl<T: Local> Global for Vec<T> { } LL | impl<T: Local> Global for Vec<T> { }
| ^^^^^^^^^^^^^^^------^^^^^---^^^ | ^^^^^^^^^^^^^^^------^^^^^---^^^
| | | | | |
@ -9,19 +12,15 @@ LL | impl<T: Local> Global for Vec<T> { }
| |
= 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 = 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
= 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` = 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`
help: move the `impl` block outside of this function `main`
--> $DIR/generics.rs:6:1
|
LL | fn main() {
| ^^^^^^^^^
LL | trait Local {};
| ----------- may need to be moved as well
= 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> = 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>
= note: `#[warn(non_local_definitions)]` on by default = note: `#[warn(non_local_definitions)]` on by default
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
--> $DIR/generics.rs:20:5 --> $DIR/generics.rs:20:5
| |
LL | fn bad() {
| -------- move the `impl` block outside of this function `bad`
LL | struct Local;
LL | impl Uto7 for Test where Local: std::any::Any {} LL | impl Uto7 for Test where Local: std::any::Any {}
| ^^^^^----^^^^^---- | ^^^^^----^^^^^----
| | | | | |
@ -30,13 +29,6 @@ LL | impl Uto7 for Test where Local: std::any::Any {}
| |
= 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 = 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
= 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` = 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`
help: move the `impl` block outside of this function `bad`
--> $DIR/generics.rs:18:1
|
LL | fn bad() {
| ^^^^^^^^
LL | struct Local;
| ------------ may need to be moved as well
= 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> = 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>
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
@ -55,107 +47,5 @@ LL | impl<T> Uto8 for T {}
= 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` = 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`
= 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> = 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>
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item warning: 3 warnings emitted
--> $DIR/generics.rs:32:5
|
LL | impl Default for UwU<OwO> {
| ^^^^^-------^^^^^---^^^^^
| | |
| | `UwU` is not local
| `Default` is not local
|
= 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
= 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`
help: move the `impl` block outside of this function `fun`
--> $DIR/generics.rs:29:1
|
LL | fn fun() {
| ^^^^^^^^
LL | #[derive(Debug)]
LL | struct OwO;
| ---------- may need to be moved as well
= 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>
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
--> $DIR/generics.rs:43:5
|
LL | impl AsRef<Cat> for () {
| ^^^^^-----^^^^^^^^^^--
| | |
| | `()` is not local
| `AsRef` is not local
|
= 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
= 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`
help: move the `impl` block outside of this function `meow`
--> $DIR/generics.rs:40:1
|
LL | fn meow() {
| ^^^^^^^^^
LL | #[derive(Debug)]
LL | struct Cat;
| ---------- may need to be moved as well
= 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>
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
--> $DIR/generics.rs:54:5
|
LL | impl PartialEq<B> for G {
| ^^^^^---------^^^^^^^^-
| | |
| | `G` is not local
| `PartialEq` is not local
|
= 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
= 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`
help: move the `impl` block outside of this function `fun2`
--> $DIR/generics.rs:51:1
|
LL | fn fun2() {
| ^^^^^^^^^
LL | #[derive(Debug, Default)]
LL | struct B;
| -------- may need to be moved as well
= 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>
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
--> $DIR/generics.rs:69:5
|
LL | impl From<Wrap<Wrap<Lion>>> for () {
| ^^^^^----^^^^^^^^^^^^^^^^^^^^^^^--
| | |
| `From` is not local `()` is not local
|
= 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
= 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`
help: move the `impl` block outside of this function `rawr`
--> $DIR/generics.rs:66:1
|
LL | fn rawr() {
| ^^^^^^^^^
LL | struct Lion;
| ----------- may need to be moved as well
= 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>
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
--> $DIR/generics.rs:76:5
|
LL | impl From<()> for Wrap<Lion> {
| ^^^^^----^^^^^^^^^----^^^^^^
| | |
| | `Wrap` is not local
| `From` is not local
|
= 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
= 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`
help: move the `impl` block outside of this function `rawr`
--> $DIR/generics.rs:66:1
|
LL | fn rawr() {
| ^^^^^^^^^
LL | struct Lion;
| ----------- may need to be moved as well
= 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>
warning: 8 warnings emitted

View File

@ -10,7 +10,6 @@ mod below {
trait HasFoo {} trait HasFoo {}
impl<T> Trait<InsideMain> for &Vec<below::Type<(InsideMain, T)>> impl<T> Trait<InsideMain> for &Vec<below::Type<(InsideMain, T)>>
//~^ WARN non-local `impl` definition
where where
T: HasFoo T: HasFoo
{} {}

View File

@ -1,29 +0,0 @@
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
--> $DIR/suggest-moving-inner.rs:12:5
|
LL | impl<T> Trait<InsideMain> for &Vec<below::Type<(InsideMain, T)>>
| ^^^^^^^^-----^^^^^^^^^^^^^^^^^----------------------------------
| | |
| | `&'_ Vec<below::Type<(InsideMain, T)>>` is not local
| `Trait` is not local
|
= 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
= 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`
help: move the `impl` block outside of this function `main`
--> $DIR/suggest-moving-inner.rs:5:1
|
LL | fn main() {
| ^^^^^^^^^
LL | mod below {
LL | pub struct Type<T>(T);
| ------------------ may need to be moved as well
LL | }
LL | struct InsideMain;
| ----------------- may need to be moved as well
LL | trait HasFoo {}
| ------------ may need to be moved as well
= 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>
= note: `#[warn(non_local_definitions)]` on by default
warning: 1 warning emitted

View File

@ -10,5 +10,4 @@ impl<'a, T: 'a> Test for &[T] where &'a T: Test {}
fn main() { fn main() {
struct Local {} struct Local {}
impl Test for &Local {} impl Test for &Local {}
//~^ WARN non-local `impl` definition
} }

View File

@ -1,24 +0,0 @@
warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item
--> $DIR/trait-solver-overflow-123573.rs:12:5
|
LL | impl Test for &Local {}
| ^^^^^----^^^^^------
| | |
| | `&'_ Local` is not local
| | help: remove `&` to make the `impl` local
| `Test` is not local
|
= 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
= 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`
help: move the `impl` block outside of this function `main`
--> $DIR/trait-solver-overflow-123573.rs:10:1
|
LL | fn main() {
| ^^^^^^^^^
LL | struct Local {}
| ------------ may need to be moved as well
= 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>
= note: `#[warn(non_local_definitions)]` on by default
warning: 1 warning emitted