Skip to content

Commit

Permalink
Auto merge of rust-lang#44174 - jimmycuadra:try-from-infallible, r=sf…
Browse files Browse the repository at this point in the history
…ackler

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 rust-lang#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 rust-lang#33417.

/cc @sfackler, @scottmcm (thank you for the help!), and @aturon
  • Loading branch information
bors committed Sep 29, 2017
2 parents 6f87d20 + 27d95d3 commit b7041bf
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 48 deletions.
41 changes: 29 additions & 12 deletions src/libcore/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -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
////////////////////////////////////////////////////////////////////////////////
Expand All @@ -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)
}
}
2 changes: 2 additions & 0 deletions src/libcore/iter/range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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) => {
Expand Down
50 changes: 21 additions & 29 deletions src/libcore/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
}
}
)*}
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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);
}

Expand Down
7 changes: 2 additions & 5 deletions src/libcore/str/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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`
Expand Down Expand Up @@ -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")]
Expand Down
1 change: 0 additions & 1 deletion src/libcore/tests/char.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
10 changes: 9 additions & 1 deletion src/libcore/tests/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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]
Expand Down
8 changes: 8 additions & 0 deletions src/libstd/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit b7041bf

Please sign in to comment.