Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Neg for signed non-zero integers. #102341

Merged
merged 1 commit into from
Apr 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions library/core/src/num/nonzero.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Definitions of integer that is known not to equal zero.

use crate::fmt;
use crate::ops::{BitOr, BitOrAssign, Div, Rem};
use crate::ops::{BitOr, BitOrAssign, Div, Neg, Rem};
use crate::str::FromStr;

use super::from_str_radix;
Expand Down Expand Up @@ -664,8 +664,7 @@ macro_rules! nonzero_signed_operations {
/// assert_eq!(pos, pos.wrapping_abs());
/// assert_eq!(pos, neg.wrapping_abs());
/// assert_eq!(min, min.wrapping_abs());
/// # // FIXME: add once Neg is implemented?
/// # // assert_eq!(max, (-max).wrapping_abs());
/// assert_eq!(max, (-max).wrapping_abs());
/// # Some(())
/// # }
/// ```
Expand Down Expand Up @@ -868,6 +867,20 @@ macro_rules! nonzero_signed_operations {
unsafe { $Ty::new_unchecked(result) }
}
}

#[stable(feature = "signed_nonzero_neg", since = "CURRENT_RUSTC_VERSION")]
impl Neg for $Ty {
type Output = $Ty;

#[inline]
fn neg(self) -> $Ty {
// SAFETY: negation of nonzero cannot yield zero values.
unsafe { $Ty::new_unchecked(self.get().neg()) }
}
}

forward_ref_unop! { impl Neg, neg for $Ty,
#[stable(feature = "signed_nonzero_neg", since = "CURRENT_RUSTC_VERSION")] }
)+
}
}
Expand Down
18 changes: 18 additions & 0 deletions library/core/tests/nonzero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,3 +336,21 @@ fn test_nonzero_uint_rem() {
let x: u32 = 42u32 % nz;
assert_eq!(x, 2u32);
}

#[test]
fn test_signed_nonzero_neg() {
assert_eq!((-NonZeroI8::new(1).unwrap()).get(), -1);
assert_eq!((-NonZeroI8::new(-1).unwrap()).get(), 1);

assert_eq!((-NonZeroI16::new(1).unwrap()).get(), -1);
assert_eq!((-NonZeroI16::new(-1).unwrap()).get(), 1);

assert_eq!((-NonZeroI32::new(1).unwrap()).get(), -1);
assert_eq!((-NonZeroI32::new(-1).unwrap()).get(), 1);

assert_eq!((-NonZeroI64::new(1).unwrap()).get(), -1);
assert_eq!((-NonZeroI64::new(-1).unwrap()).get(), 1);

assert_eq!((-NonZeroI128::new(1).unwrap()).get(), -1);
assert_eq!((-NonZeroI128::new(-1).unwrap()).get(), 1);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also add a test for overflow behavior: what happens if you negate the smallest possible value (e.g. NonZeroI64::new(i64::MIN))?

Copy link
Contributor Author

@jmillikin jmillikin Oct 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

The test asserts that for MIN and MAX, the behavior on overflow is the same as for the underlying primitve.

Edit: per discussion, replaced with a UI test to verify correct panic message on overflow.

12 changes: 12 additions & 0 deletions tests/ui/numbers-arithmetic/overflowing-neg-nonzero.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// run-fail
// error-pattern:thread 'main' panicked at 'attempt to negate with overflow'
// ignore-emscripten no processes
// compile-flags: -C debug-assertions

#![allow(arithmetic_overflow)]

use std::num::NonZeroI8;

fn main() {
let _x = -NonZeroI8::new(i8::MIN).unwrap();
}