From 09a0e241c2a42a1fdd2ca7989133ea31371a4529 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 19 Jan 2023 20:51:13 -0800 Subject: [PATCH 01/12] Avoid non-local definitions in functions --- .../0000-avoid-nonlocal-definitions-in-fns.md | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 text/0000-avoid-nonlocal-definitions-in-fns.md diff --git a/text/0000-avoid-nonlocal-definitions-in-fns.md b/text/0000-avoid-nonlocal-definitions-in-fns.md new file mode 100644 index 00000000000..8f875c10c71 --- /dev/null +++ b/text/0000-avoid-nonlocal-definitions-in-fns.md @@ -0,0 +1,57 @@ +- Feature Name: N/A +- Start Date: 2022-01-19 +- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) + +# Summary +[summary]: #summary + +Starting in Rust 2024, stop allowing items inside functions to implement +methods or traits that are visible outside the function. + +# Motivation +[motivation]: #motivation + +Currently, tools cross-referencing uses and definitions (such as IDEs) must +search inside all function bodies to find potential definitions corresponding +to uses within a function. + +Humans cross-referencing such uses and definitions may find themselves +similarly baffled. + +With this change, both humans and tools can limit the scope of their search and +avoid looking for definitions inside other functions. + +# Explanation +[explanation]: #explanation + +Starting in the Rust 2024 edition: +- An item nested inside a `fn` (through any level of nesting) may not define an + `impl Type` block unless the `Type` is also nested inside the same `fn`. +- An item nested inside a `fn` (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 `fn`. + +Rust 2015, 2018, and 2021 continue to permit this, but will produce a +warn-by-default lint. + +# 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. + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +We'll need a crater run to look at how widespread this pattern is in existing +code. + +# 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. From 632d8c9639c2327fa2aa4ad590213ec06308d084 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 19 Jan 2023 20:58:28 -0800 Subject: [PATCH 02/12] Set RFC number --- ...ions-in-fns.md => 3373-avoid-nonlocal-definitions-in-fns.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename text/{0000-avoid-nonlocal-definitions-in-fns.md => 3373-avoid-nonlocal-definitions-in-fns.md} (96%) diff --git a/text/0000-avoid-nonlocal-definitions-in-fns.md b/text/3373-avoid-nonlocal-definitions-in-fns.md similarity index 96% rename from text/0000-avoid-nonlocal-definitions-in-fns.md rename to text/3373-avoid-nonlocal-definitions-in-fns.md index 8f875c10c71..62cbd21026e 100644 --- a/text/0000-avoid-nonlocal-definitions-in-fns.md +++ b/text/3373-avoid-nonlocal-definitions-in-fns.md @@ -1,6 +1,6 @@ - Feature Name: N/A - Start Date: 2022-01-19 -- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- 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 From 5d5304ee6561f6e5891cfc0275404a256d03ace7 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 19 Jan 2023 23:22:19 -0800 Subject: [PATCH 03/12] Clarify that tools don't *have* to be looking for these definitions --- text/3373-avoid-nonlocal-definitions-in-fns.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/text/3373-avoid-nonlocal-definitions-in-fns.md b/text/3373-avoid-nonlocal-definitions-in-fns.md index 62cbd21026e..28a5161fe85 100644 --- a/text/3373-avoid-nonlocal-definitions-in-fns.md +++ b/text/3373-avoid-nonlocal-definitions-in-fns.md @@ -13,14 +13,16 @@ methods or traits that are visible outside the function. [motivation]: #motivation Currently, tools cross-referencing uses and definitions (such as IDEs) must -search inside all function bodies to find potential definitions corresponding -to uses within a function. +either search inside all function bodies to find potential definitions +corresponding to uses within a function, or not cross-reference those +definitions at all. Humans cross-referencing such uses and definitions may find themselves similarly baffled. With this change, both humans and tools can limit the scope of their search and -avoid looking for definitions inside other functions. +avoid looking for definitions inside other functions, without missing any +relevant definitions. # Explanation [explanation]: #explanation From 85c784915b9c91da6707b17908fb3234899fe735 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 19 Jan 2023 23:26:00 -0800 Subject: [PATCH 04/12] Address closures as well --- text/3373-avoid-nonlocal-definitions-in-fns.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/text/3373-avoid-nonlocal-definitions-in-fns.md b/text/3373-avoid-nonlocal-definitions-in-fns.md index 28a5161fe85..22a0ce530ad 100644 --- a/text/3373-avoid-nonlocal-definitions-in-fns.md +++ b/text/3373-avoid-nonlocal-definitions-in-fns.md @@ -28,11 +28,12 @@ relevant definitions. [explanation]: #explanation Starting in the Rust 2024 edition: -- An item nested inside a `fn` (through any level of nesting) may not define an - `impl Type` block unless the `Type` is also nested inside the same `fn`. -- An item nested inside a `fn` (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 `fn`. +- An item nested inside a function or closure (through any level of nesting) + may not define an `impl Type` block unless the `Type` is also nested inside + the same function or closure. +- An item nested inside a function or closure (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 function or closure. Rust 2015, 2018, and 2021 continue to permit this, but will produce a warn-by-default lint. From c29d41c9a7ff76ad969a05db4961ffab079dca45 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 19 Jan 2023 23:27:46 -0800 Subject: [PATCH 05/12] Note that no other language feature has this issue --- text/3373-avoid-nonlocal-definitions-in-fns.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/text/3373-avoid-nonlocal-definitions-in-fns.md b/text/3373-avoid-nonlocal-definitions-in-fns.md index 22a0ce530ad..b3c1efbad14 100644 --- a/text/3373-avoid-nonlocal-definitions-in-fns.md +++ b/text/3373-avoid-nonlocal-definitions-in-fns.md @@ -38,6 +38,9 @@ Starting in the Rust 2024 edition: Rust 2015, 2018, and 2021 continue to permit this, but will produce a warn-by-default lint. +No other language features provide a means of defining a name inside a function +and referencing that name outside the function. + # Drawbacks [drawbacks]: #drawbacks From 22ac79856b37c5b419aa24274ea893a8f71b550e Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 20 Jan 2023 03:08:30 -0800 Subject: [PATCH 06/12] Address macros --- text/3373-avoid-nonlocal-definitions-in-fns.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/text/3373-avoid-nonlocal-definitions-in-fns.md b/text/3373-avoid-nonlocal-definitions-in-fns.md index b3c1efbad14..2395979af70 100644 --- a/text/3373-avoid-nonlocal-definitions-in-fns.md +++ b/text/3373-avoid-nonlocal-definitions-in-fns.md @@ -34,6 +34,9 @@ Starting in the Rust 2024 edition: - An item nested inside a function or closure (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 function or closure. +- An item nested inside a function or closure (through any level of nesting) + may not define an exported macro visible outside the function or closure + (e.g. using `#[macro_export]`). Rust 2015, 2018, and 2021 continue to permit this, but will produce a warn-by-default lint. From 66ef4636aa848ae95912b984e9996a06cb5b2e4e Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 20 Jan 2023 03:18:18 -0800 Subject: [PATCH 07/12] Handle other expression-containing items (static, const, enum discriminants) --- .../3373-avoid-nonlocal-definitions-in-fns.md | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/text/3373-avoid-nonlocal-definitions-in-fns.md b/text/3373-avoid-nonlocal-definitions-in-fns.md index 2395979af70..7661ee9388f 100644 --- a/text/3373-avoid-nonlocal-definitions-in-fns.md +++ b/text/3373-avoid-nonlocal-definitions-in-fns.md @@ -6,44 +6,49 @@ # Summary [summary]: #summary -Starting in Rust 2024, stop allowing items inside functions to implement -methods or traits that are visible outside the function. +Starting in Rust 2024, stop allowing items inside functions or expressions to +implement methods or traits that are visible outside the function or +expression. # Motivation [motivation]: #motivation Currently, tools cross-referencing uses and definitions (such as IDEs) must -either search inside all function bodies to find potential definitions -corresponding to uses within a function, or not cross-reference those -definitions at all. +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. With this change, both humans and tools can limit the scope of their search and -avoid looking for definitions inside other functions, without missing any -relevant definitions. +avoid looking for definitions inside other functions or items, without missing +any relevant definitions. # 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`/`const` items +- The discriminant values assigned to `enum` variants + Starting in the Rust 2024 edition: -- An item nested inside a function or closure (through any level of nesting) - may not define an `impl Type` block unless the `Type` is also nested inside - the same function or closure. -- An item nested inside a function or closure (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 function or closure. -- An item nested inside a function or closure (through any level of nesting) - may not define an exported macro visible outside the function or closure - (e.g. using `#[macro_export]`). +- 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]`). Rust 2015, 2018, and 2021 continue to permit this, but will produce a warn-by-default lint. -No other language features provide a means of defining a name inside a function -and referencing that name outside the function. - # Drawbacks [drawbacks]: #drawbacks From 218949d35cfe6f075079f74efc805acb3c0c53af Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 3 Jan 2024 08:29:08 -0800 Subject: [PATCH 08/12] 3373: Change to a warn-by-default lint --- .../3373-avoid-nonlocal-definitions-in-fns.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/text/3373-avoid-nonlocal-definitions-in-fns.md b/text/3373-avoid-nonlocal-definitions-in-fns.md index 7661ee9388f..87830916922 100644 --- a/text/3373-avoid-nonlocal-definitions-in-fns.md +++ b/text/3373-avoid-nonlocal-definitions-in-fns.md @@ -6,9 +6,10 @@ # Summary [summary]: #summary -Starting in Rust 2024, stop allowing items inside functions or expressions to +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. +expression. Consider ramping that lint to deny-by-default for Rust 2024, and +evaluating a hard error for 2027. # Motivation [motivation]: #motivation @@ -21,9 +22,10 @@ not cross-reference those definitions at all. Humans cross-referencing such uses and definitions may find themselves similarly baffled. -With this change, both humans and tools can limit the scope of their search and -avoid looking for definitions inside other functions or items, without missing -any relevant definitions. +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 @@ -35,7 +37,7 @@ expressions, including the definitions of other items: - The values assigned to `static`/`const` items - The discriminant values assigned to `enum` variants -Starting in the Rust 2024 edition: +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. @@ -46,8 +48,9 @@ Starting in the Rust 2024 edition: nesting) may not define an exported macro visible outside the expression-containing item (e.g. using `#[macro_export]`). -Rust 2015, 2018, and 2021 continue to permit this, but will produce a -warn-by-default lint. +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. # Drawbacks [drawbacks]: #drawbacks From d1e9965b586ff99afc22212db81763f21d61c935 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 3 Jan 2024 08:37:43 -0800 Subject: [PATCH 09/12] 3373: Add prior art --- text/3373-avoid-nonlocal-definitions-in-fns.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/text/3373-avoid-nonlocal-definitions-in-fns.md b/text/3373-avoid-nonlocal-definitions-in-fns.md index 87830916922..94d8896a511 100644 --- a/text/3373-avoid-nonlocal-definitions-in-fns.md +++ b/text/3373-avoid-nonlocal-definitions-in-fns.md @@ -60,6 +60,14 @@ 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 From 01045be42831fe5db310afffac4b9866b9028405 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 3 Jan 2024 08:39:20 -0800 Subject: [PATCH 10/12] 3373: Define which token the lint attaches to --- text/3373-avoid-nonlocal-definitions-in-fns.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/text/3373-avoid-nonlocal-definitions-in-fns.md b/text/3373-avoid-nonlocal-definitions-in-fns.md index 94d8896a511..b61b1564153 100644 --- a/text/3373-avoid-nonlocal-definitions-in-fns.md +++ b/text/3373-avoid-nonlocal-definitions-in-fns.md @@ -52,6 +52,9 @@ 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 From 4d28f578053c42b34d5f00145645730da6c4bd92 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 3 Jan 2024 08:39:50 -0800 Subject: [PATCH 11/12] 3373: Allow definitions in anonymous `const` items --- text/3373-avoid-nonlocal-definitions-in-fns.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/3373-avoid-nonlocal-definitions-in-fns.md b/text/3373-avoid-nonlocal-definitions-in-fns.md index b61b1564153..ef76d85293e 100644 --- a/text/3373-avoid-nonlocal-definitions-in-fns.md +++ b/text/3373-avoid-nonlocal-definitions-in-fns.md @@ -34,7 +34,7 @@ The following types of items, "expression-containing items", can contain expressions, including the definitions of other items: - Functions - Closures -- The values assigned to `static`/`const` items +- 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: From e2ae261370a45001d2f41542104fe5020545e380 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 3 Jan 2024 08:40:55 -0800 Subject: [PATCH 12/12] 3373: Add unresolved question about anonymous `const` items --- text/3373-avoid-nonlocal-definitions-in-fns.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/text/3373-avoid-nonlocal-definitions-in-fns.md b/text/3373-avoid-nonlocal-definitions-in-fns.md index ef76d85293e..af36f61caf2 100644 --- a/text/3373-avoid-nonlocal-definitions-in-fns.md +++ b/text/3373-avoid-nonlocal-definitions-in-fns.md @@ -77,6 +77,9 @@ the signature without reflecting those properties in the signature. 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