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

More const int functions #66884

Closed
wants to merge 14 commits into from
1 change: 1 addition & 0 deletions src/libcore/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@
#![feature(maybe_uninit_slice)]
#![feature(external_doc)]
#![feature(associated_type_bounds)]
#![feature(const_if_match)]

#[prelude_import]
#[allow(unused)]
Expand Down
170 changes: 109 additions & 61 deletions src/libcore/num/mod.rs

Large diffs are not rendered by default.

31 changes: 20 additions & 11 deletions src/libcore/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,11 @@ impl<T> Option<T> {
/// ```
///
/// [`Some`]: #variant.Some
#[rustc_const_unstable(feature = "const_option_match")]
#[must_use = "if you intended to assert that this has a value, consider `.unwrap()` instead"]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_some(&self) -> bool {
pub const fn is_some(&self) -> bool {
9999years marked this conversation as resolved.
Show resolved Hide resolved
match *self {
Some(_) => true,
None => false,
Expand All @@ -206,11 +207,12 @@ impl<T> Option<T> {
/// ```
///
/// [`None`]: #variant.None
#[rustc_const_unstable(feature = "const_option_match")]
#[must_use = "if you intended to assert that this doesn't have a value, consider \
`.and_then(|| panic!(\"`Option` had a value when expected `None`\"))` instead"]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_none(&self) -> bool {
pub const fn is_none(&self) -> bool {
!self.is_some()
}

Expand Down Expand Up @@ -267,9 +269,10 @@ impl<T> Option<T> {
/// let text_length: Option<usize> = text.as_ref().map(|s| s.len());
/// println!("still can print text: {:?}", text);
/// ```
#[rustc_const_unstable(feature = "const_option_match")]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn as_ref(&self) -> Option<&T> {
pub const fn as_ref(&self) -> Option<&T> {
match *self {
Some(ref x) => Some(x),
None => None,
Expand Down Expand Up @@ -340,9 +343,10 @@ impl<T> Option<T> {
/// let x: Option<&str> = None;
/// x.expect("the world is ending"); // panics with `the world is ending`
/// ```
#[rustc_const_unstable(feature = "const_option_match")]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn expect(self, msg: &str) -> T {
pub const fn expect(self, msg: &str) -> T {
match self {
Some(val) => val,
None => expect_failed(msg),
Copy link
Contributor

Choose a reason for hiding this comment

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

expect_failed is not const fn

Expand Down Expand Up @@ -396,9 +400,10 @@ impl<T> Option<T> {
/// assert_eq!(Some("car").unwrap_or("bike"), "car");
/// assert_eq!(None.unwrap_or("bike"), "bike");
/// ```
#[rustc_const_unstable(feature = "const_option_match")]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn unwrap_or(self, default: T) -> T {
pub const fn unwrap_or(self, default: T) -> T {
match self {
Some(x) => x,
None => default,
Expand Down Expand Up @@ -519,9 +524,10 @@ impl<T> Option<T> {
/// let x: Option<&str> = None;
/// assert_eq!(x.ok_or(0), Err(0));
/// ```
#[rustc_const_unstable(feature = "const_option_match")]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn ok_or<E>(self, err: E) -> Result<T, E> {
pub const fn ok_or<E>(self, err: E) -> Result<T, E> {
match self {
Some(v) => Ok(v),
None => Err(err),
Expand Down Expand Up @@ -624,9 +630,10 @@ impl<T> Option<T> {
/// let y: Option<&str> = None;
/// assert_eq!(x.and(y), None);
/// ```
#[rustc_const_unstable(feature = "const_option_match")]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn and<U>(self, optb: Option<U>) -> Option<U> {
pub const fn and<U>(self, optb: Option<U>) -> Option<U> {
match self {
Some(_) => optb,
None => None,
Expand Down Expand Up @@ -724,9 +731,10 @@ impl<T> Option<T> {
/// let y = None;
/// assert_eq!(x.or(y), None);
/// ```
#[rustc_const_unstable(feature = "const_option_match")]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn or(self, optb: Option<T>) -> Option<T> {
pub const fn or(self, optb: Option<T>) -> Option<T> {
match self {
Some(_) => self,
None => optb,
Expand Down Expand Up @@ -779,9 +787,10 @@ impl<T> Option<T> {
/// let y: Option<u32> = None;
/// assert_eq!(x.xor(y), None);
/// ```
#[rustc_const_unstable(feature = "const_option_match")]
#[inline]
#[stable(feature = "option_xor", since = "1.37.0")]
pub fn xor(self, optb: Option<T>) -> Option<T> {
pub const fn xor(self, optb: Option<T>) -> Option<T> {
match (self, optb) {
(Some(a), None) => Some(a),
(None, Some(b)) => Some(b),
Expand Down Expand Up @@ -1172,14 +1181,14 @@ impl<T, E> Option<Result<T, E>> {
/// ```
#[inline]
#[stable(feature = "transpose_result", since = "1.33.0")]
pub fn transpose(self) -> Result<Option<T>, E> {
#[rustc_const_unstable(feature = "const_option_match")]
pub const fn transpose(self) -> Result<Option<T>, E> {
match self {
Some(Ok(x)) => Ok(Some(x)),
Some(Err(e)) => Err(e),
None => Ok(None),
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

you lost a closing bracket


// This is a separate function to reduce the code size of .expect() itself.
#[inline(never)]
Expand Down
17 changes: 17 additions & 0 deletions src/test/ui/consts/auxiliary/const_assert_lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/// Given a block of const bindings, asserts that their values (calculated at runtime) are the
/// same as their values (calculated at compile-time).
macro_rules! assert_same_const {
($(const $ident:ident: $ty:ty = $exp:expr;)+) => {
$(const $ident: $ty = $exp;)+

pub fn main() {
$({
// Assign the expr to a variable at runtime; otherwise, the argument is
// calculated at compile-time, making the test useless.
let tmp = $exp;
assert_eq!(tmp, $ident);
})+
}
}
}

57 changes: 57 additions & 0 deletions src/test/ui/consts/const-int-checked.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// run-pass
#![feature(const_int_checked)]

macro_rules! assert_same_const {
($(const $ident:ident: $ty:ty = $exp:expr;)+) => {
$(const $ident: $ty = $exp;)+

pub fn main() {
$(assert_eq!($exp, $ident);)+
9999years marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

assert_same_const! {
const CHECKED_ADD_I32_A: Option<i32> = 5i32.checked_add(2);
const CHECKED_ADD_I8_A: Option<i8> = 127i8.checked_add(2);
const CHECKED_ADD_U8_A: Option<u8> = 255u8.checked_add(2);

const CHECKED_SUB_I32_A: Option<i32> = 5i32.checked_sub(2);
const CHECKED_SUB_I8_A: Option<i8> = (-127 as i8).checked_sub(2);
const CHECKED_SUB_U8_A: Option<u8> = 1u8.checked_sub(2);

const CHECKED_MUL_I32_A: Option<i32> = 5i32.checked_mul(7777);
const CHECKED_MUL_I8_A: Option<i8> = (-127 as i8).checked_mul(-99);
const CHECKED_MUL_U8_A: Option<u8> = 1u8.checked_mul(3);

// Needs intrinsics::unchecked_div.
// const CHECKED_DIV_I32_A: Option<i32> = 5i32.checked_div(7777);
// const CHECKED_DIV_I8_A: Option<i8> = (-127 as i8).checked_div(-99);
// const CHECKED_DIV_U8_A: Option<u8> = 1u8.checked_div(3);

// Needs intrinsics::unchecked_rem.
// const CHECKED_REM_I32_A: Option<i32> = 5i32.checked_rem(7777);
// const CHECKED_REM_I8_A: Option<i8> = (-127 as i8).checked_rem(-99);
// const CHECKED_REM_U8_A: Option<u8> = 1u8.checked_rem(3);
// const CHECKED_REM_U8_B: Option<u8> = 1u8.checked_rem(0);

const CHECKED_NEG_I32_A: Option<i32> = 5i32.checked_neg();
const CHECKED_NEG_I8_A: Option<i8> = (-127 as i8).checked_neg();
const CHECKED_NEG_U8_A: Option<u8> = 1u8.checked_neg();
const CHECKED_NEG_U8_B: Option<u8> = u8::min_value().checked_neg();

const CHECKED_SHL_I32_A: Option<i32> = 5i32.checked_shl(77777);
const CHECKED_SHL_I8_A: Option<i8> = (-127 as i8).checked_shl(2);
const CHECKED_SHL_U8_A: Option<u8> = 1u8.checked_shl(8);
const CHECKED_SHL_U8_B: Option<u8> = 1u8.checked_shl(0);

const CHECKED_SHR_I32_A: Option<i32> = 5i32.checked_shr(77777);
const CHECKED_SHR_I8_A: Option<i8> = (-127 as i8).checked_shr(2);
const CHECKED_SHR_U8_A: Option<u8> = 1u8.checked_shr(8);
const CHECKED_SHR_U8_B: Option<u8> = 1u8.checked_shr(0);

const CHECKED_ABS_I32_A: Option<i32> = 5i32.checked_abs();
const CHECKED_ABS_I8_A: Option<i8> = (-127 as i8).checked_abs();
const CHECKED_ABS_I8_B: Option<i8> = 1i8.checked_abs();
const CHECKED_ABS_I8_C: Option<i8> = i8::min_value().checked_abs();
}
44 changes: 44 additions & 0 deletions src/test/ui/consts/const-int-euclidean.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// run-pass
// aux-build:const_assert_lib.rs
use const_assert_lib::assert_same_const;

#![feature(const_int_euclidean)]
#![feature(saturating_neg)]

assert_same_const! {
const CHECKED_DIV_I32_A: Option<i32> = 5i32.checked_div_euclid(7777);
const CHECKED_DIV_I8_A: Option<i8> = (-127 as i8).checked_div_euclid(-99);
const CHECKED_DIV_I8_B: Option<i8> = (-127 as i8).checked_div_euclid(1);
const CHECKED_DIV_I8_C: Option<i8> = i8::min_value().checked_div_euclid(-1);
const CHECKED_DIV_U8_A: Option<u8> = 1u8.checked_div_euclid(3);

const CHECKED_REM_I32_A: Option<i32> = 5i32.checked_rem_euclid(7777);
const CHECKED_REM_I8_A: Option<i8> = (-127 as i8).checked_rem_euclid(-99);
const CHECKED_REM_I8_B: Option<i8> = (-127 as i8).checked_rem_euclid(0);
const CHECKED_REM_I8_C: Option<i8> = i8::min_value().checked_rem_euclid(-1);
const CHECKED_REM_U8_A: Option<u8> = 1u8.checked_rem_euclid(3);

const WRAPPING_DIV_I32_A: i32 = 5i32.wrapping_div_euclid(7777);
const WRAPPING_DIV_I8_A: i8 = (-127 as i8).wrapping_div_euclid(-99);
const WRAPPING_DIV_I8_B: i8 = (-127 as i8).wrapping_div_euclid(1);
const WRAPPING_DIV_I8_C: i8 = i8::min_value().wrapping_div_euclid(-1);
const WRAPPING_DIV_U8_A: u8 = 1u8.wrapping_div_euclid(3);

const WRAPPING_REM_I32_A: i32 = 5i32.wrapping_rem_euclid(7777);
const WRAPPING_REM_I8_A: i8 = (-127 as i8).wrapping_rem_euclid(-99);
const WRAPPING_REM_I8_B: i8 = (-127 as i8).wrapping_rem_euclid(1);
const WRAPPING_REM_I8_C: i8 = i8::min_value().wrapping_rem_euclid(-1);
const WRAPPING_REM_U8_A: u8 = 1u8.wrapping_rem_euclid(3);

const OVERFLOWING_DIV_I32_A: (i32, bool) = 5i32.overflowing_div_euclid(7777);
const OVERFLOWING_DIV_I8_A: (i8, bool) = (-127 as i8).overflowing_div_euclid(-99);
const OVERFLOWING_DIV_I8_B: (i8, bool) = (-127 as i8).overflowing_div_euclid(1);
const OVERFLOWING_DIV_I8_C: (i8, bool) = i8::min_value().overflowing_div_euclid(-1);
const OVERFLOWING_DIV_U8_A: (u8, bool) = 1u8.overflowing_div_euclid(3);

const OVERFLOWING_REM_I32_A: (i32, bool) = 5i32.overflowing_rem_euclid(7777);
const OVERFLOWING_REM_I8_A: (i8, bool) = (-127 as i8).overflowing_rem_euclid(-99);
const OVERFLOWING_REM_I8_B: (i8, bool) = (-127 as i8).overflowing_rem_euclid(1);
const OVERFLOWING_REM_I8_C: (i8, bool) = i8::min_value().overflowing_rem_euclid(-1);
const OVERFLOWING_REM_U8_A: (u8, bool) = 1u8.overflowing_rem_euclid(3);
}
40 changes: 40 additions & 0 deletions src/test/ui/consts/const-int-nonzero.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// run-pass
// aux-build:const_assert_lib.rs
use const_assert_lib::assert_same_const;

#![feature(const_int_nonzero)]

use std::num::{
NonZeroI8,
NonZeroU8,
NonZeroI32,
NonZeroUsize,
};

assert_same_const! {
const NON_ZERO_NEW_1: Option<NonZeroI8> = NonZeroI8::new(1);
const NON_ZERO_NEW_2: Option<NonZeroI8> = NonZeroI8::new(0);
const NON_ZERO_NEW_3: Option<NonZeroI8> = NonZeroI8::new(-38);
const NON_ZERO_NEW_4: Option<NonZeroU8> = NonZeroU8::new(1);
const NON_ZERO_NEW_5: Option<NonZeroU8> = NonZeroU8::new(0);
const NON_ZERO_NEW_6: Option<NonZeroI32> = NonZeroI32::new(1);
const NON_ZERO_NEW_7: Option<NonZeroI32> = NonZeroI32::new(0);
const NON_ZERO_NEW_8: Option<NonZeroI32> = NonZeroI32::new(-38);
const NON_ZERO_NEW_9: Option<NonZeroUsize> = NonZeroUsize::new(1);
const NON_ZERO_NEW_10: Option<NonZeroUsize> = NonZeroUsize::new(0);

// Option::unwrap isn't supported in const yet, so we use new_unchecked.
const NON_ZERO_GET_1: i8 = unsafe { NonZeroI8::new_unchecked(1) }.get();
const NON_ZERO_GET_2: i8 = unsafe { NonZeroI8::new_unchecked(-38) }.get();
const NON_ZERO_GET_3: u8 = unsafe { NonZeroU8::new_unchecked(1) }.get();
const NON_ZERO_GET_4: i32 = unsafe { NonZeroI32::new_unchecked(1) }.get();
const NON_ZERO_GET_5: i32 = unsafe { NonZeroI32::new_unchecked(-38) }.get();
const NON_ZERO_GET_6: usize = unsafe { NonZeroUsize::new_unchecked(1) }.get();

const NON_ZERO_NEW_UNCHECKED_1: NonZeroI8 = unsafe { NonZeroI8::new_unchecked(1) };
const NON_ZERO_NEW_UNCHECKED_2: NonZeroI8 = unsafe { NonZeroI8::new_unchecked(-38) };
const NON_ZERO_NEW_UNCHECKED_3: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(1) };
const NON_ZERO_NEW_UNCHECKED_4: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(1) };
const NON_ZERO_NEW_UNCHECKED_5: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(-38) };
const NON_ZERO_NEW_UNCHECKED_6: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(1) };
}
25 changes: 25 additions & 0 deletions src/test/ui/consts/const-int-overflowing-rpass.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// run-pass
#![feature(const_int_overflowing)]

const ADD_A: (u32, bool) = 5u32.overflowing_add(2);
const ADD_B: (u32, bool) = u32::max_value().overflowing_add(1);
Expand All @@ -22,6 +23,18 @@ const ABS_POS: (i32, bool) = 10i32.overflowing_abs();
const ABS_NEG: (i32, bool) = (-10i32).overflowing_abs();
const ABS_MIN: (i32, bool) = i32::min_value().overflowing_abs();

const DIV_A: (i8, bool) = 8i8.overflowing_div(2);
const DIV_B: (i8, bool) = 8i8.overflowing_div(3);
const DIV_C: (i8, bool) = i8::min_value().overflowing_div(-1i8);
const DIV_D: (u8, bool) = 8u8.overflowing_div(2);
const DIV_E: (u8, bool) = 8u8.overflowing_div(3);

const REM_A: (i8, bool) = 8i8.overflowing_rem(2);
const REM_B: (i8, bool) = 8i8.overflowing_rem(3);
const REM_C: (i8, bool) = i8::min_value().overflowing_rem(-1i8);
const REM_D: (u8, bool) = 8u8.overflowing_rem(2);
const REM_E: (u8, bool) = 8u8.overflowing_rem(3);

fn main() {
assert_eq!(ADD_A, (7, false));
assert_eq!(ADD_B, (0, true));
Expand All @@ -44,4 +57,16 @@ fn main() {
assert_eq!(ABS_POS, (10, false));
assert_eq!(ABS_NEG, (10, false));
assert_eq!(ABS_MIN, (i32::min_value(), true));

assert_eq!(DIV_A, (4i8, false));
assert_eq!(DIV_B, (2i8, false));
assert_eq!(DIV_C, (i8::min_value(), true));
assert_eq!(DIV_D, (4u8, false));
assert_eq!(DIV_E, (2u8, false));

assert_eq!(REM_A, (0i8, false));
assert_eq!(REM_B, (2i8, false));
assert_eq!(REM_C, (0i8, true));
assert_eq!(REM_D, (0u8, false));
assert_eq!(REM_E, (2u8, false));
}
4 changes: 4 additions & 0 deletions src/test/ui/consts/const-int-pow-rpass.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
// run-pass
// #![feature(const_int_pow)]
#![feature(wrapping_next_power_of_two)]

const IS_POWER_OF_TWO_A: bool = 0u32.is_power_of_two();
const IS_POWER_OF_TWO_B: bool = 32u32.is_power_of_two();
const IS_POWER_OF_TWO_C: bool = 33u32.is_power_of_two();
const IS_POWER_OF_TWO_D: bool = 3u8.is_power_of_two();

fn main() {
assert!(!IS_POWER_OF_TWO_A);
assert!(IS_POWER_OF_TWO_B);
assert!(!IS_POWER_OF_TWO_C);
assert!(!IS_POWER_OF_TWO_D);
}
Loading