about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-05-23 16:19:15 +0000
committerbors <bors@rust-lang.org>2024-05-23 16:19:15 +0000
commit76856ffb576fb2dff472481a6389d42ca836db6f (patch)
treedfe9e1d8f6d0a2e1f6090bf231d593155f6e28c7
parent05c40536285245d31f2bd6ed43c5bc43cc768752 (diff)
parentcfa150b0ddc28ea3723a3b4d0916e729dcea3246 (diff)
downloadrust-76856ffb576fb2dff472481a6389d42ca836db6f.tar.gz
rust-76856ffb576fb2dff472481a6389d42ca836db6f.zip
Auto merge of #12833 - kpreid:empty-enum-doc, r=Manishearth
Rephrase and expand `empty_enum` documentation.

* Remove incorrect claim that “wrappers around it are the conventional way to define an uninhabited type”.
* Discuss why one would use `!`, a newtype struct, or keep the enum.
* Add links to relevant documentation.

Before writing this change, I asked the community via [IRLO](https://internals.rust-lang.org/t/idiomatic-definition-of-uninhabited-never-newtypes/20877) and [Zulip](https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/Never.20type.20wrappers.20.2F.20defining.20uninhabited.20newtypes) for feedback. The broad consensus seemed to me to be that in a world where both `never_type` and `min_exhaustive_patterns` are stable and therefore available for general use, we _might_ want to `!` or newtypes of it — but it's certainly not “conventional” _yet._ Therefore, I've removed “conventional” and added a discussion of the pros and cons of different choices.

changelog: [`empty_enum`]: expanded documentation
-rw-r--r--clippy_lints/src/empty_enum.rs45
1 files changed, 33 insertions, 12 deletions
diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs
index 420888b6ccb..d16714695cb 100644
--- a/clippy_lints/src/empty_enum.rs
+++ b/clippy_lints/src/empty_enum.rs
@@ -7,32 +7,53 @@ use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for `enum`s with no variants.
+    /// Checks for `enum`s with no variants, which therefore are uninhabited types
+    /// (cannot be instantiated).
     ///
-    /// As of this writing, the `never_type` is still a
-    /// nightly-only experimental API. Therefore, this lint is only triggered
-    /// if the `never_type` is enabled.
+    /// As of this writing, the `never_type` is still a nightly-only experimental API.
+    /// Therefore, this lint is only triggered if `#![feature(never_type)]` is enabled.
     ///
     /// ### Why is this bad?
-    /// If you want to introduce a type which
-    /// can't be instantiated, you should use `!` (the primitive type "never"),
-    /// or a wrapper around it, because `!` has more extensive
-    /// compiler support (type inference, etc...) and wrappers
-    /// around it are the conventional way to define an uninhabited type.
-    /// For further information visit [never type documentation](https://doc.rust-lang.org/std/primitive.never.html)
+    /// * If you only want a type which can’t be instantiated, you should use [`!`]
+    ///   (the primitive type "never"), because [`!`] has more extensive compiler support
+    ///   (type inference, etc.) and implementations of common traits.
     ///
+    /// * If you need to introduce a distinct type, consider using a [newtype] `struct`
+    ///   containing [`!`] instead (`struct MyType(pub !)`), because it is more idiomatic
+    ///   to use a `struct` rather than an `enum` when an `enum` is unnecessary.
+    ///
+    ///   If you do this, note that the [visibility] of the [`!`] field determines whether
+    ///   the uninhabitedness is visible in documentation, and whether it can be pattern
+    ///   matched to mark code unreachable. If the field is not visible, then the struct
+    ///   acts like any other struct with private fields.
+    ///
+    /// * If the enum has no variants only because all variants happen to be
+    ///   [disabled by conditional compilation][cfg], then it would be appropriate
+    ///   to allow the lint, with `#[allow(empty_enum)]`.
+    ///
+    /// For further information, visit
+    /// [the never type’s documentation][`!`].
     ///
     /// ### Example
     /// ```no_run
-    /// enum Test {}
+    /// enum CannotExist {}
     /// ```
     ///
     /// Use instead:
     /// ```no_run
     /// #![feature(never_type)]
     ///
-    /// struct Test(!);
+    /// /// Use the `!` type directly...
+    /// type CannotExist = !;
+    ///
+    /// /// ...or define a newtype which is distinct.
+    /// struct CannotExist2(pub !);
     /// ```
+    ///
+    /// [`!`]: https://doc.rust-lang.org/std/primitive.never.html
+    /// [cfg]: https://doc.rust-lang.org/reference/conditional-compilation.html
+    /// [newtype]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#using-the-newtype-pattern-for-type-safety-and-abstraction
+    /// [visibility]: https://doc.rust-lang.org/reference/visibility-and-privacy.html
     #[clippy::version = "pre 1.29.0"]
     pub EMPTY_ENUM,
     pedantic,