You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Go over all libstd traits and see which of them !/TyNever should implement #35866
I went through all of the traits in the standard library, here is my analysis:
Most traits which make sense to implement for ! are already implemented
Because ! inherently relates to dead code it's very hard to come up with actual use-cases
There are a lot of traits which could be implemented for !, but why would you need it?
IMO it's better to go on a case-by-case basis. I.e. if there is a use case for a certain trait to be implemented, implement it specifically, rather than trying to implement all that could be implemented.
Activity
Jules-Bertholet commentedon Jul 3, 2023
@rustbot label F-never_type
WaffleLapkin commentedon Oct 18, 2025
The conditions under which it is reasonable for
!to implement a trait are:SelfI went through all of the traits in the standard library, here is my analysis:
!are already implemented!inherently relates to dead code it's very hard to come up with actual use-cases!, but why would you need it?IMO it's better to go on a case-by-case basis. I.e. if there is a use case for a certain trait to be implemented, implement it specifically, rather than trying to implement all that could be implemented.
Here is a table with all traits in
std:std::alloc::GlobalAllocstaticwith a value ofSelf, which is not possible for!std::alloc::Allocatorstd::any::Anystd::ascii::AsciiExtstd::borrow::Borrowstd::borrow::BorrowMutstd::borrow::ToOwnedstd::clone::Clonestd::clone::CloneToUninitstd::clone::UseClonedstd::cmp::Eqstd::cmp::Ordstd::cmp::PartialEqstd::cmp::PartialOrdstd::convert::AsMutstd::convert::AsRefstd::convert::FromT -> !.for<T> From<!> for Tcould make sense, but it overlaps withfor<T> From<T> for Tand thus isn't happeningstd::convert::IntoFromstd::convert::TryFromFromstd::convert::TryIntoFromstd::convert::FloatToInt!is not a floatstd::default::Defaultdefaultdoesn't take an argument of typeSelfstd::error::Errorstd::ffi::VaArgSafe!in varargs...std::fmt::BinaryDebug/Display, but why notstd::fmt::Debugstd::fmt::Displaystd::fmt::LowerExpDebug/Display, but why notstd::fmt::LowerHexDebug/Display, but why notstd::fmt::OctalDebug/Display, but why notstd::fmt::PointerDebug/Display, but why notstd::fmt::UpperExpDebug/Display, but why notstd::fmt::UpperHexDebug/Display, but why notstd::fmt::Writestd::future::Futurestd::future::IntoFuturestd::future::AsyncDropstd::hash::BuildHasherstd::hash::Hashstd::hash::Hasherstd::io::BufReadstd::io::IsTerminalstd::io::Readstd::io::Seekstd::io::Writestd::iter::DoubleEndedIteratorstd::iter::ExactSizeIteratorstd::iter::Extendstd::iter::FromIteratorfrom_iterdoesn't accept an argument of typeSelfstd::iter::FusedIteratorstd::iter::IntoIteratorstd::iter::Iteratorstd::iter::Productproductdoesn't accept an argument of typeSelfstd::iter::Sumsumdoesn't accept an argument of typeSelfstd::iter::Stepstd::iter::TrustedLenstd::iter::TrustedStepstd::marker::Copystd::marker::Sendstd::marker::Sizedstd::marker::Syncstd::marker::Unpinstd::marker::ConstParamTy_!, so you can't pass it as a const generic parameterstd::marker::Destructstd::marker::DiscriminantKindstd::marker::FnPtrFnPtrseems to only be used as a bound forfn_addr_eqand is perma-unstable. there is never a need for the!implstd::marker::Freezestd::marker::MetaSizedstd::marker::PointeeSizedstd::marker::StructuralPartialEq!=> that'd be uselessstd::marker::Tuplestd::marker::Unsizestd::marker::UnsizedConstParamTyConstParamTy_?std::marker::Variancestd::mem::TransmuteFrom!std::net::ToSocketAddrsstd::num::ZeroablePrimitive!is never validstd::ops::*Assignstd::ops::Notstd::ops::NegNot? There hasn't been a feature request for that yet...std::ops::Drop!: Copystd::ops::RangeBoundsstd::ops::CoerceUnsizedstd::ops::DispatchFromDynstd::ops::IntoBoundsstd::ops::OneSidedRangestd::ops::*(the rest)std::panic::RefUnwindSafestd::panic::UnwindSafestd::pin::PinCoerceUnsizedstd::process::Terminationstd::ptr::Pointeestd::slice::SliceIndexstd::slice::Concatstd::slice::Joinstd::std::FromStr!can't be constructed and thus can't be parsedstd::string::ToStringstd::sync::atomic::AtomicPrimitivestd::task::Wakestd::task::LocalWakestd::async_iter::AsyncIteratorstd::async_iter::IntoAsyncIteratorstd::random::Distributionstd::random::RandomSourcestd::range::IntoBoundsstd::range::OneSidedRangestd::range::RangeBoundsstd::range::Stepstd::simd::*Footnotes
and there are multiple potential choices for it ↩
!already implements this traits ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13 ↩14 ↩15 ↩16 ↩17 ↩18 ↩19 ↩20 ↩21 ↩22 ↩23 ↩24 ↩25 ↩26I don't see a usecase, but it's possible ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13 ↩14 ↩15 ↩16 ↩17 ↩18 ↩19 ↩20 ↩21 ↩22
https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=c1b0e0dc1208eb8871b7e22712768fb9 ↩
possible to implement, but useless ↩
technically it's possible to have
for<T> !: Add<T, Output = T>, but why would you need this?... ↩