Skip to content

Commit

Permalink
Add lossless integer conversion by reference
Browse files Browse the repository at this point in the history
  • Loading branch information
vandenheuvel committed Nov 10, 2021
1 parent 800a156 commit 998914f
Show file tree
Hide file tree
Showing 7 changed files with 322 additions and 1 deletion.
27 changes: 27 additions & 0 deletions library/core/src/convert/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ macro_rules! impl_from {
small as Self
}
}

impl_from_ref! { $Small, $Large }
};
($Small: ty, $Large: ty, #[$attr:meta]) => {
impl_from!($Small,
Expand All @@ -68,6 +70,21 @@ macro_rules! impl_from {
}
}

macro_rules! impl_from_ref {
($Small: ty, $Large: ty) => {
#[stable(feature = "num_from_num_ref", since = "1.60.0")]
#[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")]
#[doc = concat!("Converts `&", stringify!($Small), "` to `", stringify!($Large), "` losslessly.")]
#[doc = concat!("See the documentation of the `", stringify!($Small), "` to `", stringify!($Large), "` conversion.")]
impl const From<&$Small> for $Large {
#[inline]
fn from(small: &$Small) -> Self {
From::from(*small)
}
}
}
}

macro_rules! impl_from_bool {
($target: ty, #[$attr:meta]) => {
impl_from!(bool, $target, #[$attr], concat!("Converts a `bool` to a `",
Expand Down Expand Up @@ -98,30 +115,40 @@ impl_from_bool! { i128, #[stable(feature = "from_bool", since = "1.28.0")] }
impl_from_bool! { isize, #[stable(feature = "from_bool", since = "1.28.0")] }

// Unsigned -> Unsigned
impl_from_ref! { u8, u8 }
impl_from! { u8, u16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u8, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u8, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u8, u128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from! { u8, usize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from_ref! { u16, u16 }
impl_from! { u16, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u16, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u16, u128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from_ref! { u32, u32 }
impl_from! { u32, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { u32, u128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from_ref! { u64, u64 }
impl_from! { u64, u128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from_ref! { u128, u128 }

// Signed -> Signed
impl_from_ref! { i8, i8 }
impl_from! { i8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { i8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { i8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { i8, i128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from! { i8, isize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from_ref! { i16, i16 }
impl_from! { i16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { i16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { i16, i128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from_ref! { i32, i32 }
impl_from! { i32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
impl_from! { i32, i128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from_ref! { i64, i64 }
impl_from! { i64, i128, #[stable(feature = "i128", since = "1.26.0")] }
impl_from_ref! { i128, i128 }

// Unsigned -> Signed
impl_from! { u8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] }
Expand Down
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
#![feature(const_bigint_helper_methods)]
#![feature(const_caller_location)]
#![feature(const_cell_into_inner)]
#![feature(const_convert)]
#![feature(const_discriminant)]
#![cfg_attr(not(bootstrap), feature(const_eval_select))]
#![feature(const_float_bits_conv)]
Expand Down
35 changes: 35 additions & 0 deletions src/test/ui/num-from-num-ref/allowed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// check-pass

fn main () {
// same size, signed
let _: i8 = From::from(&1_i8);
let _: i16 = From::from(&1_i16);
let _: i32 = From::from(&1_i32);
let _: i64 = From::from(&1_i64);
let _: i128 = From::from(&1_i128);

// same size, unsigned
let _: u8 = From::from(&1_u8);
let _: u16 = From::from(&1_u16);
let _: u32 = From::from(&1_u32);
let _: u64 = From::from(&1_u64);
let _: u128 = From::from(&1_u128);

// smaller, signed
let _: i16 = From::from(&1_i8);
let _: i32 = From::from(&1_i16);
let _: i64 = From::from(&1_i32);
let _: i128 = From::from(&1_i64);

// smaller, unsigned
let _: u16 = From::from(&1_u8);
let _: u32 = From::from(&1_u16);
let _: u64 = From::from(&1_u32);
let _: u128 = From::from(&1_u64);

// mixed signs
let _: i16 = From::from(&1_u8);
let _: i32 = From::from(&1_u16);
let _: i64 = From::from(&1_u32);
let _: i128 = From::from(&1_u64);
}
22 changes: 22 additions & 0 deletions src/test/ui/num-from-num-ref/illegal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Check that conversions by reference which are not lossless are not implemented.

fn main () {
// larger, signed
let _: i8 = From::from(&1_i16); //~ ERROR
let _: i16 = From::from(&1_i32); //~ ERROR
let _: i32 = From::from(&1_i64); //~ ERROR
let _: i64 = From::from(&1_i128); //~ ERROR

// larger, unsigned
let _: u8 = From::from(&1_u16); //~ ERROR
let _: u16 = From::from(&1_u32); //~ ERROR
let _: u32 = From::from(&1_u64); //~ ERROR
let _: u64 = From::from(&1_u128); //~ ERROR

// mixed signs
let _: i8 = From::from(&1_u8); //~ ERROR
let _: u16 = From::from(&1_i8); //~ ERROR
let _: i32 = From::from(&1_u32); //~ ERROR
let _: u64 = From::from(&1_i32); //~ ERROR
let _: i128 = From::from(&1_u128); //~ ERROR
}
234 changes: 234 additions & 0 deletions src/test/ui/num-from-num-ref/illegal.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
error[E0277]: the trait bound `i8: From<&i16>` is not satisfied
--> $DIR/illegal.rs:5:17
|
LL | let _: i8 = From::from(&1_i16);
| ^^^^^^^^^^ the trait `From<&i16>` is not implemented for `i8`
|
= help: the following implementations were found:
<i8 as From<&bool>>
<i8 as From<&i8>>
<i8 as From<NonZeroI8>>
<i8 as From<bool>>
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `i16: From<&i32>` is not satisfied
--> $DIR/illegal.rs:6:18
|
LL | let _: i16 = From::from(&1_i32);
| ^^^^^^^^^^ the trait `From<&i32>` is not implemented for `i16`
|
= help: the following implementations were found:
<i16 as From<&bool>>
<i16 as From<&i16>>
<i16 as From<&i8>>
<i16 as From<&u8>>
and 4 others
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `i32: From<&i64>` is not satisfied
--> $DIR/illegal.rs:7:18
|
LL | let _: i32 = From::from(&1_i64);
| ^^^^^^^^^^ the trait `From<&i64>` is not implemented for `i32`
|
= help: the following implementations were found:
<i32 as From<&bool>>
<i32 as From<&i16>>
<i32 as From<&i32>>
<i32 as From<&i8>>
and 8 others
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `i64: From<&i128>` is not satisfied
--> $DIR/illegal.rs:8:18
|
LL | let _: i64 = From::from(&1_i128);
| ^^^^^^^^^^ the trait `From<&i128>` is not implemented for `i64`
|
= help: the following implementations were found:
<i64 as From<&bool>>
<i64 as From<&i16>>
<i64 as From<&i32>>
<i64 as From<&i64>>
and 12 others
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `u8: From<&u16>` is not satisfied
--> $DIR/illegal.rs:11:17
|
LL | let _: u8 = From::from(&1_u16);
| ^^^^^^^^^^ the trait `From<&u16>` is not implemented for `u8`
|
= help: the following implementations were found:
<u8 as From<&bool>>
<u8 as From<&u8>>
<u8 as From<NonZeroU8>>
<u8 as From<bool>>
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `u16: From<&u32>` is not satisfied
--> $DIR/illegal.rs:12:18
|
LL | let _: u16 = From::from(&1_u32);
| ^^^^^^^^^^ the trait `From<&u32>` is not implemented for `u16`
|
= help: the following implementations were found:
<u16 as From<&bool>>
<u16 as From<&u16>>
<u16 as From<&u8>>
<u16 as From<NonZeroU16>>
and 2 others
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `u32: From<&u64>` is not satisfied
--> $DIR/illegal.rs:13:18
|
LL | let _: u32 = From::from(&1_u64);
| ^^^^^^^^^^ the trait `From<&u64>` is not implemented for `u32`
|
= help: the following implementations were found:
<u32 as From<&bool>>
<u32 as From<&u16>>
<u32 as From<&u32>>
<u32 as From<&u8>>
and 6 others
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `u64: From<&u128>` is not satisfied
--> $DIR/illegal.rs:14:18
|
LL | let _: u64 = From::from(&1_u128);
| ^^^^^^^^^^ the trait `From<&u128>` is not implemented for `u64`
|
= help: the following implementations were found:
<u64 as From<&bool>>
<u64 as From<&u16>>
<u64 as From<&u32>>
<u64 as From<&u64>>
and 7 others
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `i8: From<&u8>` is not satisfied
--> $DIR/illegal.rs:17:17
|
LL | let _: i8 = From::from(&1_u8);
| ^^^^^^^^^^ the trait `From<&u8>` is not implemented for `i8`
|
= help: the following implementations were found:
<i8 as From<&bool>>
<i8 as From<&i8>>
<i8 as From<NonZeroI8>>
<i8 as From<bool>>
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `u16: From<&i8>` is not satisfied
--> $DIR/illegal.rs:18:18
|
LL | let _: u16 = From::from(&1_i8);
| ^^^^^^^^^^ the trait `From<&i8>` is not implemented for `u16`
|
= help: the following implementations were found:
<u16 as From<&bool>>
<u16 as From<&u16>>
<u16 as From<&u8>>
<u16 as From<NonZeroU16>>
and 2 others
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `i32: From<&u32>` is not satisfied
--> $DIR/illegal.rs:19:18
|
LL | let _: i32 = From::from(&1_u32);
| ^^^^^^^^^^ the trait `From<&u32>` is not implemented for `i32`
|
= help: the following implementations were found:
<i32 as From<&bool>>
<i32 as From<&i16>>
<i32 as From<&i32>>
<i32 as From<&i8>>
and 8 others
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `u64: From<&i32>` is not satisfied
--> $DIR/illegal.rs:20:18
|
LL | let _: u64 = From::from(&1_i32);
| ^^^^^^^^^^ the trait `From<&i32>` is not implemented for `u64`
|
= help: the following implementations were found:
<u64 as From<&bool>>
<u64 as From<&u16>>
<u64 as From<&u32>>
<u64 as From<&u64>>
and 7 others
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `i128: From<&u128>` is not satisfied
--> $DIR/illegal.rs:21:19
|
LL | let _: i128 = From::from(&1_u128);
| ^^^^^^^^^^ the trait `From<&u128>` is not implemented for `i128`
|
= help: the following implementations were found:
<i128 as From<&bool>>
<i128 as From<&i128>>
<i128 as From<&i16>>
<i128 as From<&i32>>
and 16 others
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 13 previous errors

For more information about this error, try `rustc --explain E0277`.
2 changes: 1 addition & 1 deletion src/test/ui/traits/issue-77982.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect(
- impl From<NonZeroU32> for u32;
- impl From<bool> for u32;
- impl From<char> for u32;
and 3 more
and 7 more
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
Expand Down
2 changes: 2 additions & 0 deletions src/test/ui/try-trait/bad-interconversion.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ LL | Ok(Err(123_i32)?)
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= help: the following implementations were found:
<u8 as From<&bool>>
<u8 as From<&u8>>
<u8 as From<NonZeroU8>>
<u8 as From<bool>>
= note: required because of the requirements on the impl of `FromResidual<Result<Infallible, i32>>` for `Result<u64, u8>`
Expand Down

0 comments on commit 998914f

Please sign in to comment.