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 1 commit
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
93 changes: 93 additions & 0 deletions src/libcore/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,3 +499,96 @@ 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 {}
}
}

use fmt;
Copy link
Member

Choose a reason for hiding this comment

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

Could this be moved up to the top of the file?


#[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?

3 changes: 1 addition & 2 deletions src/libstd/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ use iter::{self, FusedIterator};
use ops::{self, Deref};
use rc::Rc;
use str::FromStr;
use string::ParseError;
use sync::Arc;

use ffi::{OsStr, OsString};
Expand Down Expand Up @@ -1453,7 +1452,7 @@ impl From<String> for PathBuf {

#[stable(feature = "path_from_str", since = "1.32.0")]
impl FromStr for PathBuf {
type Err = ParseError;
type Err = core::convert::Infallible;

fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(PathBuf::from(s))
Expand Down