Auto merge of #44174 - jimmycuadra:try-from-infallible, r=sfackler
Add blanket TryFrom impl when From is implemented. Adds `impl<T, U> TryFrom<T> for U where U: From<T>`. Removes `impl<'a, T> TryFrom<&'a str> for T where T: FromStr` (originally added in #40281) due to overlapping impls caused by the new blanket impl. This removal is to be discussed further on the tracking issue for TryFrom. Refs #33417. /cc @sfackler, @scottmcm (thank you for the help!), and @aturon
This commit is contained in:
commit
b7041bfab3
7 changed files with 71 additions and 48 deletions
|
@ -48,8 +48,25 @@
|
|||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use str::FromStr;
|
||||
use fmt;
|
||||
|
||||
/// A type used as the error type for implementations of fallible conversion
|
||||
/// traits in cases where conversions cannot actually fail.
|
||||
///
|
||||
/// Because `Infallible` has no variants, a value of this type can never exist.
|
||||
/// It is used only to satisfy trait signatures that expect an error type, and
|
||||
/// signals to both the compiler and the user that the error case is impossible.
|
||||
#[unstable(feature = "try_from", issue = "33417")]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub enum Infallible {}
|
||||
|
||||
#[unstable(feature = "try_from", issue = "33417")]
|
||||
impl fmt::Display for Infallible {
|
||||
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
}
|
||||
}
|
||||
}
|
||||
/// A cheap reference-to-reference conversion. Used to convert a value to a
|
||||
/// reference value within generic code.
|
||||
///
|
||||
|
@ -417,6 +434,17 @@ impl<T, U> TryInto<U> for T where U: TryFrom<T>
|
|||
}
|
||||
}
|
||||
|
||||
// Infallible conversions are semantically equivalent to fallible conversions
|
||||
// with an uninhabited error type.
|
||||
#[unstable(feature = "try_from", issue = "33417")]
|
||||
impl<T, U> TryFrom<U> for T where T: From<U> {
|
||||
type Error = Infallible;
|
||||
|
||||
fn try_from(value: U) -> Result<Self, Self::Error> {
|
||||
Ok(T::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// CONCRETE IMPLS
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -442,14 +470,3 @@ impl AsRef<str> for str {
|
|||
self
|
||||
}
|
||||
}
|
||||
|
||||
// FromStr implies TryFrom<&str>
|
||||
#[unstable(feature = "try_from", issue = "33417")]
|
||||
impl<'a, T> TryFrom<&'a str> for T where T: FromStr
|
||||
{
|
||||
type Error = <T as FromStr>::Err;
|
||||
|
||||
fn try_from(s: &'a str) -> Result<T, Self::Error> {
|
||||
FromStr::from_str(s)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,6 +89,7 @@ macro_rules! step_impl_unsigned {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(unreachable_patterns)]
|
||||
fn add_usize(&self, n: usize) -> Option<Self> {
|
||||
match <$t>::try_from(n) {
|
||||
Ok(n_as_t) => self.checked_add(n_as_t),
|
||||
|
@ -120,6 +121,7 @@ macro_rules! step_impl_signed {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(unreachable_patterns)]
|
||||
fn add_usize(&self, n: usize) -> Option<Self> {
|
||||
match <$unsigned>::try_from(n) {
|
||||
Ok(n_as_unsigned) => {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use convert::TryFrom;
|
||||
use convert::{Infallible, TryFrom};
|
||||
use fmt;
|
||||
use intrinsics;
|
||||
use str::FromStr;
|
||||
|
@ -2507,16 +2507,24 @@ impl fmt::Display for TryFromIntError {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_from", issue = "33417")]
|
||||
impl From<Infallible> for TryFromIntError {
|
||||
fn from(infallible: Infallible) -> TryFromIntError {
|
||||
match infallible {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no possible bounds violation
|
||||
macro_rules! try_from_unbounded {
|
||||
($source:ty, $($target:ty),*) => {$(
|
||||
#[unstable(feature = "try_from", issue = "33417")]
|
||||
impl TryFrom<$source> for $target {
|
||||
type Error = TryFromIntError;
|
||||
type Error = Infallible;
|
||||
|
||||
#[inline]
|
||||
fn try_from(u: $source) -> Result<$target, TryFromIntError> {
|
||||
Ok(u as $target)
|
||||
fn try_from(value: $source) -> Result<Self, Self::Error> {
|
||||
Ok(value as $target)
|
||||
}
|
||||
}
|
||||
)*}
|
||||
|
@ -2588,31 +2596,17 @@ macro_rules! rev {
|
|||
}
|
||||
|
||||
/// intra-sign conversions
|
||||
try_from_unbounded!(u8, u8, u16, u32, u64, u128);
|
||||
try_from_unbounded!(u16, u16, u32, u64, u128);
|
||||
try_from_unbounded!(u32, u32, u64, u128);
|
||||
try_from_unbounded!(u64, u64, u128);
|
||||
try_from_unbounded!(u128, u128);
|
||||
try_from_upper_bounded!(u16, u8);
|
||||
try_from_upper_bounded!(u32, u16, u8);
|
||||
try_from_upper_bounded!(u64, u32, u16, u8);
|
||||
try_from_upper_bounded!(u128, u64, u32, u16, u8);
|
||||
|
||||
try_from_unbounded!(i8, i8, i16, i32, i64, i128);
|
||||
try_from_unbounded!(i16, i16, i32, i64, i128);
|
||||
try_from_unbounded!(i32, i32, i64, i128);
|
||||
try_from_unbounded!(i64, i64, i128);
|
||||
try_from_unbounded!(i128, i128);
|
||||
try_from_both_bounded!(i16, i8);
|
||||
try_from_both_bounded!(i32, i16, i8);
|
||||
try_from_both_bounded!(i64, i32, i16, i8);
|
||||
try_from_both_bounded!(i128, i64, i32, i16, i8);
|
||||
|
||||
// unsigned-to-signed
|
||||
try_from_unbounded!(u8, i16, i32, i64, i128);
|
||||
try_from_unbounded!(u16, i32, i64, i128);
|
||||
try_from_unbounded!(u32, i64, i128);
|
||||
try_from_unbounded!(u64, i128);
|
||||
try_from_upper_bounded!(u8, i8);
|
||||
try_from_upper_bounded!(u16, i8, i16);
|
||||
try_from_upper_bounded!(u32, i8, i16, i32);
|
||||
|
@ -2631,15 +2625,13 @@ try_from_both_bounded!(i64, u32, u16, u8);
|
|||
try_from_both_bounded!(i128, u64, u32, u16, u8);
|
||||
|
||||
// usize/isize
|
||||
try_from_unbounded!(usize, usize);
|
||||
try_from_upper_bounded!(usize, isize);
|
||||
try_from_lower_bounded!(isize, usize);
|
||||
try_from_unbounded!(isize, isize);
|
||||
|
||||
#[cfg(target_pointer_width = "16")]
|
||||
mod ptr_try_from_impls {
|
||||
use super::TryFromIntError;
|
||||
use convert::TryFrom;
|
||||
use convert::{Infallible, TryFrom};
|
||||
|
||||
try_from_upper_bounded!(usize, u8);
|
||||
try_from_unbounded!(usize, u16, u32, u64, u128);
|
||||
|
@ -2651,21 +2643,21 @@ mod ptr_try_from_impls {
|
|||
try_from_both_bounded!(isize, i8);
|
||||
try_from_unbounded!(isize, i16, i32, i64, i128);
|
||||
|
||||
rev!(try_from_unbounded, usize, u8, u16);
|
||||
rev!(try_from_unbounded, usize, u16);
|
||||
rev!(try_from_upper_bounded, usize, u32, u64, u128);
|
||||
rev!(try_from_lower_bounded, usize, i8, i16);
|
||||
rev!(try_from_both_bounded, usize, i32, i64, i128);
|
||||
|
||||
rev!(try_from_unbounded, isize, u8);
|
||||
rev!(try_from_upper_bounded, isize, u16, u32, u64, u128);
|
||||
rev!(try_from_unbounded, isize, i8, i16);
|
||||
rev!(try_from_unbounded, isize, i16);
|
||||
rev!(try_from_both_bounded, isize, i32, i64, i128);
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
mod ptr_try_from_impls {
|
||||
use super::TryFromIntError;
|
||||
use convert::TryFrom;
|
||||
use convert::{Infallible, TryFrom};
|
||||
|
||||
try_from_upper_bounded!(usize, u8, u16);
|
||||
try_from_unbounded!(usize, u32, u64, u128);
|
||||
|
@ -2677,21 +2669,21 @@ mod ptr_try_from_impls {
|
|||
try_from_both_bounded!(isize, i8, i16);
|
||||
try_from_unbounded!(isize, i32, i64, i128);
|
||||
|
||||
rev!(try_from_unbounded, usize, u8, u16, u32);
|
||||
rev!(try_from_unbounded, usize, u16, u32);
|
||||
rev!(try_from_upper_bounded, usize, u64, u128);
|
||||
rev!(try_from_lower_bounded, usize, i8, i16, i32);
|
||||
rev!(try_from_both_bounded, usize, i64, i128);
|
||||
|
||||
rev!(try_from_unbounded, isize, u8, u16);
|
||||
rev!(try_from_upper_bounded, isize, u32, u64, u128);
|
||||
rev!(try_from_unbounded, isize, i8, i16, i32);
|
||||
rev!(try_from_unbounded, isize, i16, i32);
|
||||
rev!(try_from_both_bounded, isize, i64, i128);
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
mod ptr_try_from_impls {
|
||||
use super::TryFromIntError;
|
||||
use convert::TryFrom;
|
||||
use convert::{Infallible, TryFrom};
|
||||
|
||||
try_from_upper_bounded!(usize, u8, u16, u32);
|
||||
try_from_unbounded!(usize, u64, u128);
|
||||
|
@ -2703,14 +2695,14 @@ mod ptr_try_from_impls {
|
|||
try_from_both_bounded!(isize, i8, i16, i32);
|
||||
try_from_unbounded!(isize, i64, i128);
|
||||
|
||||
rev!(try_from_unbounded, usize, u8, u16, u32, u64);
|
||||
rev!(try_from_unbounded, usize, u16, u32, u64);
|
||||
rev!(try_from_upper_bounded, usize, u128);
|
||||
rev!(try_from_lower_bounded, usize, i8, i16, i32, i64);
|
||||
rev!(try_from_both_bounded, usize, i128);
|
||||
|
||||
rev!(try_from_unbounded, isize, u8, u16, u32);
|
||||
rev!(try_from_upper_bounded, isize, u64, u128);
|
||||
rev!(try_from_unbounded, isize, i8, i16, i32, i64);
|
||||
rev!(try_from_unbounded, isize, i16, i32, i64);
|
||||
rev!(try_from_both_bounded, isize, i128);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ use self::pattern::Pattern;
|
|||
use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher};
|
||||
|
||||
use char;
|
||||
use convert::TryFrom;
|
||||
use fmt;
|
||||
use iter::{Map, Cloned, FusedIterator, TrustedLen};
|
||||
use iter_private::TrustedRandomAccess;
|
||||
|
@ -2198,7 +2197,7 @@ pub trait StrExt {
|
|||
#[stable(feature = "core", since = "1.6.0")]
|
||||
fn is_empty(&self) -> bool;
|
||||
#[stable(feature = "core", since = "1.6.0")]
|
||||
fn parse<'a, T: TryFrom<&'a str>>(&'a self) -> Result<T, T::Error>;
|
||||
fn parse<T: FromStr>(&self) -> Result<T, T::Err>;
|
||||
}
|
||||
|
||||
// truncate `&str` to length at most equal to `max`
|
||||
|
@ -2518,9 +2517,7 @@ impl StrExt for str {
|
|||
fn is_empty(&self) -> bool { self.len() == 0 }
|
||||
|
||||
#[inline]
|
||||
fn parse<'a, T>(&'a self) -> Result<T, T::Error> where T: TryFrom<&'a str> {
|
||||
T::try_from(self)
|
||||
}
|
||||
fn parse<T: FromStr>(&self) -> Result<T, T::Err> { FromStr::from_str(self) }
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
@ -32,7 +32,6 @@ fn test_convert() {
|
|||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(char::from_str("a").unwrap(), 'a');
|
||||
assert_eq!(char::try_from("a").unwrap(), 'a');
|
||||
assert_eq!(char::from_str("\0").unwrap(), '\0');
|
||||
assert_eq!(char::from_str("\u{D7FF}").unwrap(), '\u{d7FF}');
|
||||
assert!(char::from_str("").is_err());
|
||||
|
|
|
@ -8,10 +8,11 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use core::convert::TryFrom;
|
||||
use core::convert::{TryFrom, TryInto};
|
||||
use core::cmp::PartialEq;
|
||||
use core::fmt::Debug;
|
||||
use core::marker::Copy;
|
||||
use core::num::TryFromIntError;
|
||||
use core::ops::{Add, Sub, Mul, Div, Rem};
|
||||
use core::option::Option;
|
||||
use core::option::Option::{Some, None};
|
||||
|
@ -134,6 +135,13 @@ fn test_empty() {
|
|||
assert_eq!("".parse::<u8>().ok(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_infallible_try_from_int_error() {
|
||||
let func = |x: i8| -> Result<i32, TryFromIntError> { Ok(x.try_into()?) };
|
||||
|
||||
assert!(func(0).is_ok());
|
||||
}
|
||||
|
||||
macro_rules! test_impl_from {
|
||||
($fn_name: ident, $Small: ty, $Large: ty) => {
|
||||
#[test]
|
||||
|
|
|
@ -56,6 +56,7 @@ use any::TypeId;
|
|||
use borrow::Cow;
|
||||
use cell;
|
||||
use char;
|
||||
use convert;
|
||||
use fmt::{self, Debug, Display};
|
||||
use mem::transmute;
|
||||
use num;
|
||||
|
@ -362,6 +363,13 @@ impl Error for char::ParseCharError {
|
|||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "try_from", issue = "33417")]
|
||||
impl Error for convert::Infallible {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copied from any.rs
|
||||
impl Error + 'static {
|
||||
|
|
Loading…
Add table
Reference in a new issue