-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge RFC 3373: Avoid non-local definitions in fns
The FCP for RFC 3373 completed on 2024-01-20 with a disposition to merge. Let's merge it.
- Loading branch information
Showing
1 changed file
with
88 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
- Tracking Issue: [rust-lang/rust#120363](https://github.com/rust-lang/rust/issues/120363) | ||
|
||
# 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. |