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

Stabilize TryFrom and TryInto with a convert::Infallible empty enum #58302

Merged
merged 5 commits into from
Feb 25, 2019
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
37 changes: 3 additions & 34 deletions src/liballoc/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ impl String {
/// [`str::from_utf8`]: ../../std/str/fn.from_utf8.html
/// [`as_bytes`]: struct.String.html#method.as_bytes
/// [`FromUtf8Error`]: struct.FromUtf8Error.html
/// [`Err`]: ../../stdresult/enum.Result.html#variant.Err
/// [`Err`]: ../../std/result/enum.Result.html#variant.Err
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error> {
Expand Down Expand Up @@ -2073,48 +2073,17 @@ impl ops::DerefMut for String {
/// [`String`]: struct.String.html
/// [`from_str`]: ../../std/str/trait.FromStr.html#tymethod.from_str
#[stable(feature = "str_parse_error", since = "1.5.0")]
#[derive(Copy)]
pub enum ParseError {}
pub type ParseError = core::convert::Infallible;

#[stable(feature = "rust1", since = "1.0.0")]
impl FromStr for String {
type Err = ParseError;
type Err = core::convert::Infallible;
#[inline]
fn from_str(s: &str) -> Result<String, ParseError> {
Ok(String::from(s))
}
}

#[stable(feature = "str_parse_error", since = "1.5.0")]
impl Clone for ParseError {
fn clone(&self) -> ParseError {
match *self {}
}
}

#[stable(feature = "str_parse_error", since = "1.5.0")]
impl fmt::Debug for ParseError {
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {}
}
}

#[stable(feature = "str_parse_error2", since = "1.8.0")]
impl fmt::Display for ParseError {
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {}
}
}

#[stable(feature = "str_parse_error", since = "1.5.0")]
impl PartialEq for ParseError {
fn eq(&self, _: &ParseError) -> bool {
match *self {}
}
}

#[stable(feature = "str_parse_error", since = "1.5.0")]
impl Eq for ParseError {}

/// A trait for converting a value to a `String`.
///
Expand Down
8 changes: 4 additions & 4 deletions src/libcore/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ unsafe impl<T, A: Unsize<[T]>> FixedSizeArray<T> for A {
}

/// The error type returned when a conversion from a slice to an array fails.
#[unstable(feature = "try_from", issue = "33417")]
#[stable(feature = "try_from", since = "1.34.0")]
#[derive(Debug, Copy, Clone)]
pub struct TryFromSliceError(());

Expand Down Expand Up @@ -138,7 +138,7 @@ macro_rules! array_impls {
}
}

#[unstable(feature = "try_from", issue = "33417")]
#[stable(feature = "try_from", since = "1.34.0")]
impl<'a, T> TryFrom<&'a [T]> for [T; $N] where T: Copy {
type Error = TryFromSliceError;

Expand All @@ -147,7 +147,7 @@ macro_rules! array_impls {
}
}

#[unstable(feature = "try_from", issue = "33417")]
#[stable(feature = "try_from", since = "1.34.0")]
impl<'a, T> TryFrom<&'a [T]> for &'a [T; $N] {
type Error = TryFromSliceError;

Expand All @@ -161,7 +161,7 @@ macro_rules! array_impls {
}
}

#[unstable(feature = "try_from", issue = "33417")]
#[stable(feature = "try_from", since = "1.34.0")]
impl<'a, T> TryFrom<&'a mut [T]> for &'a mut [T; $N] {
type Error = TryFromSliceError;

Expand Down
6 changes: 3 additions & 3 deletions src/libcore/char/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ impl FromStr for char {
}


#[unstable(feature = "try_from", issue = "33417")]
#[stable(feature = "try_from", since = "1.34.0")]
impl TryFrom<u32> for char {
type Error = CharTryFromError;

Expand All @@ -233,11 +233,11 @@ impl TryFrom<u32> for char {
}

/// The error type returned when a conversion from u32 to char fails.
#[unstable(feature = "try_from", issue = "33417")]
#[stable(feature = "try_from", since = "1.34.0")]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct CharTryFromError(());

#[unstable(feature = "try_from", issue = "33417")]
#[stable(feature = "try_from", since = "1.34.0")]
impl fmt::Display for CharTryFromError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
"converted integer out of range for `char`".fmt(f)
Expand Down
2 changes: 1 addition & 1 deletion src/libcore/char/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub use self::convert::{from_u32, from_digit};
pub use self::convert::from_u32_unchecked;
#[stable(feature = "char_from_str", since = "1.20.0")]
pub use self::convert::ParseCharError;
#[unstable(feature = "try_from", issue = "33417")]
#[stable(feature = "try_from", since = "1.34.0")]
pub use self::convert::CharTryFromError;
#[stable(feature = "decode_utf16", since = "1.9.0")]
pub use self::decode::{decode_utf16, DecodeUtf16, DecodeUtf16Error};
Expand Down
128 changes: 123 additions & 5 deletions src/libcore/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@

#![stable(feature = "rust1", since = "1.0.0")]

use fmt;

/// An identity function.
///
/// Two things are important to note about this function:
Expand Down Expand Up @@ -370,22 +372,26 @@ pub trait From<T>: Sized {
///
/// [`TryFrom`]: trait.TryFrom.html
/// [`Into`]: trait.Into.html
#[unstable(feature = "try_from", issue = "33417")]
#[stable(feature = "try_from", since = "1.34.0")]
pub trait TryInto<T>: Sized {
/// The type returned in the event of a conversion error.
#[stable(feature = "try_from", since = "1.34.0")]
type Error;

/// Performs the conversion.
#[stable(feature = "try_from", since = "1.34.0")]
fn try_into(self) -> Result<T, Self::Error>;
}

/// Attempt to construct `Self` via a conversion.
#[unstable(feature = "try_from", issue = "33417")]
#[stable(feature = "try_from", since = "1.34.0")]
pub trait TryFrom<T>: Sized {
/// The type returned in the event of a conversion error.
#[stable(feature = "try_from", since = "1.34.0")]
type Error;

/// Performs the conversion.
#[stable(feature = "try_from", since = "1.34.0")]
fn try_from(value: T) -> Result<Self, Self::Error>;
}

Expand Down Expand Up @@ -453,7 +459,7 @@ impl<T> From<T> for T {


// TryFrom implies TryInto
#[unstable(feature = "try_from", issue = "33417")]
#[stable(feature = "try_from", since = "1.34.0")]
impl<T, U> TryInto<U> for T where U: TryFrom<T>
{
type Error = U::Error;
Expand All @@ -465,9 +471,9 @@ 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")]
#[stable(feature = "try_from", since = "1.34.0")]
impl<T, U> TryFrom<U> for T where U: Into<T> {
type Error = !;
type Error = Infallible;

fn try_from(value: U) -> Result<Self, Self::Error> {
Ok(U::into(value))
Expand Down Expand Up @@ -499,3 +505,115 @@ impl AsRef<str> for str {
self
}
}

////////////////////////////////////////////////////////////////////////////////
// THE NO-ERROR ERROR TYPE
////////////////////////////////////////////////////////////////////////////////

/// The error type for errors that can never happen.
///
/// Since this enum has no variant, a value of this type can never actually exist.
/// This can be useful for generic APIs that use [`Result`] and parameterize the error type,
/// to indicate that the result is always [`Ok`].
///
/// For example, the [`TryFrom`] trait (conversion that returns a [`Result`])
/// has a blanket implementation for all types where a reverse [`Into`] implementation exists.
///
/// ```ignore (illustrates std code, duplicating the impl in a doctest would be an error)
/// impl<T, U> TryFrom<U> for T where U: Into<T> {
/// type Error = Infallible;
///
/// fn try_from(value: U) -> Result<Self, Infallible> {
/// Ok(U::into(value)) // Never returns `Err`
/// }
/// }
/// ```
///
/// # Future compatibility
///
/// This enum has the same role as [the `!` “never” type][never],
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe using regular quotes instead? "never"

/// which is unstable in this version of Rust.
/// When `!` is stabilized, we plan to make `Infallible` a type alias to it:
///
/// ```ignore (illustrates future std change)
/// pub type Infallible = !;
/// ```
///
/// … and eventually deprecate `Infallible`.
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe using three plain dots

///
///
/// However there is one case where `!` syntax can be used
/// before `!` is stabilized as a full-fleged type: in the position of a function’s return type.
Copy link
Contributor

Choose a reason for hiding this comment

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

'

Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
/// before `!` is stabilized as a full-fleged type: in the position of a function’s return type.
/// before `!` is stabilized as a full-fledged type: in the position of a function’s return type.

"full-fledged" still looks wrong to me as a NZer, but Merriam-Webster seems to imply that "fully-fledged" is only a British thing.

/// Specifically, it is possible implementations for two different function pointer types:
///
/// ```
/// trait MyTrait {}
/// impl MyTrait for fn() -> ! {}
/// impl MyTrait for fn() -> std::convert::Infallible {}
/// ```
///
/// With `Infallible` being an enum, this code is valid.
/// However when `Infallible` becomes an alias for the never type,
/// the two `impl`s will start to overlap
/// and therefore will be disallowed by the language’s trait coherence rules.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we want to add something here that says “so, uh, don’t do this?”. Wording suggestions welcome.

Copy link
Member

Choose a reason for hiding this comment

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

Is using one over the other preferable? Either way, maybe the answer to that should be in the docs.

Copy link
Contributor

Choose a reason for hiding this comment

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

'

///
/// [`Ok`]: ../result/enum.Result.html#variant.Ok
/// [`Result`]: ../result/enum.Result.html
/// [`TryFrom`]: trait.TryFrom.html
/// [`Into`]: trait.Into.html
/// [never]: ../../std/primitive.never.html
#[stable(feature = "convert_infallible", since = "1.34.0")]
#[derive(Copy)]
pub enum Infallible {}

#[stable(feature = "convert_infallible", since = "1.34.0")]
impl Clone for Infallible {
fn clone(&self) -> Infallible {
match *self {}
}
}

#[stable(feature = "convert_infallible", since = "1.34.0")]
impl fmt::Debug for Infallible {
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {}
}
}

#[stable(feature = "convert_infallible", since = "1.34.0")]
impl fmt::Display for Infallible {
fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {}
}
}

#[stable(feature = "convert_infallible", since = "1.34.0")]
impl PartialEq for Infallible {
fn eq(&self, _: &Infallible) -> bool {
match *self {}
}
}

#[stable(feature = "convert_infallible", since = "1.34.0")]
impl Eq for Infallible {}
Copy link
Member

Choose a reason for hiding this comment

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

With PartialEq and Eq perhaps the Ord-style traits could be included as well?


#[stable(feature = "convert_infallible", since = "1.34.0")]
impl PartialOrd for Infallible {
fn partial_cmp(&self, _other: &Self) -> Option<crate::cmp::Ordering> {
match *self {}
}
}

#[stable(feature = "convert_infallible", since = "1.34.0")]
impl Ord for Infallible {
fn cmp(&self, _other: &Self) -> crate::cmp::Ordering {
match *self {}
}
}

#[stable(feature = "convert_infallible", since = "1.34.0")]
impl From<!> for Infallible {
fn from(x: !) -> Self {
x
}
}
Loading