diff --git a/text/3373-avoid-nonlocal-definitions-in-fns.md b/text/3373-avoid-nonlocal-definitions-in-fns.md new file mode 100644 index 00000000000..af36f61caf2 --- /dev/null +++ b/text/3373-avoid-nonlocal-definitions-in-fns.md @@ -0,0 +1,88 @@ +- Feature Name: N/A +- Start Date: 2022-01-19 +- RFC PR: [rust-lang/rfcs#3373](https://github.com/rust-lang/rfcs/pull/3373) +- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) + +# Summary +[summary]: #summary + +Add a warn-by-default lint for items inside functions or expressions that +implement methods or traits that are visible outside the function or +expression. Consider ramping that lint to deny-by-default for Rust 2024, and +evaluating a hard error for 2027. + +# Motivation +[motivation]: #motivation + +Currently, tools cross-referencing uses and definitions (such as IDEs) must +either search inside all function bodies and other expression-containing items +to find potential definitions corresponding to uses within another function, or +not cross-reference those definitions at all. + +Humans cross-referencing such uses and definitions may find themselves +similarly baffled. + +This change helps humans limit the scope of their search and avoid looking for +definitions inside other functions or items, without missing any relevant +definitions. If in the future we manage to forbid it entirely within a +subsequent Rust edtion, tools will be able to rely on this as well. + +# Explanation +[explanation]: #explanation + +The following types of items, "expression-containing items", can contain +expressions, including the definitions of other items: +- Functions +- Closures +- The values assigned to `static` items or non-anonymous `const` items. +- The discriminant values assigned to `enum` variants + +Rust will emit a warn-by-default lint for all of the following cases: +- An item nested inside an expression-containing item (through any level of + nesting) may not define an `impl Type` block unless the `Type` is also nested + inside the same expression-containing item. +- An item nested inside an expression-containing item (through any level of + nesting) may not define an `impl Trait for Type` unless either the `Trait` or + the `Type` is also nested inside the same expression-containing item. +- An item nested inside an expression-containing item (through any level of + nesting) may not define an exported macro visible outside the + expression-containing item (e.g. using `#[macro_export]`). + +In a future edition, we may consider making this lint deny-by-default, or +eventually making it a hard error. We'll evaluate the impact on the ecosystem +and existing use cases before doing so. + +The lint is considered to attach to the `impl` token of an `impl` block, or the +`macro_rules!` token of a macro definition. + +# Drawbacks +[drawbacks]: #drawbacks + +Some existing code makes use of this pattern, and would need to migrate to a +different pattern. In particular, this pattern may occur in macro-generated +code, or in code generated by tools like rustdoc. Making this change would +require such code and tools to restructure to meet this requirement. + +# Prior art +[prior-art]: #prior-art + +Other aspects of Rust's design attempt to enable local reasoning and avoid +global reasoning, including non-inference of function signatures, and not +having the function body affect non-opaque properties of `impl Trait` uses in +the signature without reflecting those properties in the signature. + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +We'll need a crater run to look at how widespread this pattern is in existing +code. + +Should we flag these definitions in anonymous `const` items as well, or would +that produce unwanted warnings? + +# Future possibilities +[future-possibilities]: #future-possibilities + +If in the future Rust provides a "standalone `derive`" mechanism (e.g. `derive +Trait for Type` as a standalone definition separate from `Type`), the `impl` +produced by that mechanism would be subject to the same requirements.