Auto merge of #58302 - SimonSapin:tryfrom, r=alexcrichton

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

This is the plan proposed in https://github.com/rust-lang/rust/issues/33417#issuecomment-423073898
This commit is contained in:
bors
2019-02-25 20:24:10 +00:00
16 changed files with 163 additions and 79 deletions
+3 -34
View File
@@ -486,7 +486,7 @@ pub fn from_str(_: &str) -> 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> {
@@ -2073,48 +2073,17 @@ fn deref_mut(&mut self) -> &mut str {
/// [`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`.
///
+4 -4
View File
@@ -49,7 +49,7 @@ fn as_mut_slice(&mut self) -> &mut [T] {
}
/// 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(());
@@ -138,7 +138,7 @@ fn borrow_mut(&mut self) -> &mut [T] {
}
}
#[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;
@@ -147,7 +147,7 @@ fn borrow_mut(&mut self) -> &mut [T] {
}
}
#[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;
@@ -161,7 +161,7 @@ fn borrow_mut(&mut self) -> &mut [T] {
}
}
#[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;
+3 -3
View File
@@ -218,7 +218,7 @@ fn from_str(s: &str) -> Result<Self, Self::Err> {
}
#[unstable(feature = "try_from", issue = "33417")]
#[stable(feature = "try_from", since = "1.34.0")]
impl TryFrom<u32> for char {
type Error = CharTryFromError;
@@ -233,11 +233,11 @@ fn try_from(i: u32) -> Result<Self, Self::Error> {
}
/// 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)
+1 -1
View File
@@ -30,7 +30,7 @@
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};
+123 -5
View File
@@ -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:
@@ -367,22 +369,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>;
}
@@ -450,7 +456,7 @@ fn from(t: T) -> T { 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;
@@ -462,9 +468,9 @@ fn try_into(self) -> Result<U, U::Error> {
// 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))
@@ -496,3 +502,115 @@ fn as_ref(&self) -> &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],
/// 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`.
///
///
/// However there is one case where `!` syntax can be used
/// before `!` is stabilized as a full-fleged type: in the position of a functions return type.
/// 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 languages trait coherence rules.
///
/// [`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 {}
#[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
}
}
+19 -15
View File
@@ -2,7 +2,7 @@
#![stable(feature = "rust1", since = "1.0.0")]
use convert::TryFrom;
use convert::{TryFrom, Infallible};
use fmt;
use intrinsics;
use mem;
@@ -2000,7 +2000,6 @@ pub const fn is_negative(self) -> bool { self < 0 }
When starting from a slice rather than an array, fallible conversion APIs can be used:
```
#![feature(try_from)]
use std::convert::TryInto;
fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
@@ -2032,7 +2031,6 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
When starting from a slice rather than an array, fallible conversion APIs can be used:
```
#![feature(try_from)]
use std::convert::TryInto;
fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
@@ -2074,7 +2072,6 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
When starting from a slice rather than an array, fallible conversion APIs can be used:
```
#![feature(try_from)]
use std::convert::TryInto;
fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
@@ -3767,7 +3764,6 @@ pub fn wrapping_next_power_of_two(self) -> Self {
When starting from a slice rather than an array, fallible conversion APIs can be used:
```
#![feature(try_from)]
use std::convert::TryInto;
fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
@@ -3799,7 +3795,6 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
When starting from a slice rather than an array, fallible conversion APIs can be used:
```
#![feature(try_from)]
use std::convert::TryInto;
fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
@@ -3841,7 +3836,6 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
When starting from a slice rather than an array, fallible conversion APIs can be used:
```
#![feature(try_from)]
use std::convert::TryInto;
fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {
@@ -4504,7 +4498,7 @@ fn from_str(src: &str) -> Result<Self, ParseIntError> {
from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 }
/// The error type returned when a checked integral type conversion fails.
#[unstable(feature = "try_from", issue = "33417")]
#[stable(feature = "try_from", since = "1.34.0")]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct TryFromIntError(());
@@ -4519,24 +4513,34 @@ pub fn __description(&self) -> &str {
}
}
#[unstable(feature = "try_from", issue = "33417")]
#[stable(feature = "try_from", since = "1.34.0")]
impl fmt::Display for TryFromIntError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.__description().fmt(fmt)
}
}
#[unstable(feature = "try_from", issue = "33417")]
#[stable(feature = "try_from", since = "1.34.0")]
impl From<Infallible> for TryFromIntError {
fn from(x: Infallible) -> TryFromIntError {
match x {}
}
}
#[unstable(feature = "never_type", issue = "35121")]
impl From<!> for TryFromIntError {
fn from(never: !) -> TryFromIntError {
never
// Match rather than coerce to make sure that code like
// `From<Infallible> for TryFromIntError` above will keep working
// when `Infallible` becomes an alias to `!`.
match never {}
}
}
// no possible bounds violation
macro_rules! try_from_unbounded {
($source:ty, $($target:ty),*) => {$(
#[unstable(feature = "try_from", issue = "33417")]
#[stable(feature = "try_from", since = "1.34.0")]
impl TryFrom<$source> for $target {
type Error = TryFromIntError;
@@ -4551,7 +4555,7 @@ fn try_from(value: $source) -> Result<Self, Self::Error> {
// only negative bounds
macro_rules! try_from_lower_bounded {
($source:ty, $($target:ty),*) => {$(
#[unstable(feature = "try_from", issue = "33417")]
#[stable(feature = "try_from", since = "1.34.0")]
impl TryFrom<$source> for $target {
type Error = TryFromIntError;
@@ -4570,7 +4574,7 @@ fn try_from(u: $source) -> Result<$target, TryFromIntError> {
// unsigned to signed (only positive bound)
macro_rules! try_from_upper_bounded {
($source:ty, $($target:ty),*) => {$(
#[unstable(feature = "try_from", issue = "33417")]
#[stable(feature = "try_from", since = "1.34.0")]
impl TryFrom<$source> for $target {
type Error = TryFromIntError;
@@ -4589,7 +4593,7 @@ fn try_from(u: $source) -> Result<$target, TryFromIntError> {
// all other cases
macro_rules! try_from_both_bounded {
($source:ty, $($target:ty),*) => {$(
#[unstable(feature = "try_from", issue = "33417")]
#[stable(feature = "try_from", since = "1.34.0")]
impl TryFrom<$source> for $target {
type Error = TryFromIntError;
-1
View File
@@ -26,7 +26,6 @@
#![feature(str_internals)]
#![feature(test)]
#![feature(trusted_len)]
#![feature(try_from)]
#![feature(try_trait)]
#![feature(align_offset)]
#![feature(reverse_bits)]
-1
View File
@@ -35,7 +35,6 @@
#![deny(rust_2018_idioms)]
#![feature(nll)]
#![feature(try_from)]
// See librustc_cratesio_shim/Cargo.toml for a comment explaining this.
#[allow(unused_extern_crates)]
extern crate rustc_cratesio_shim;
-1
View File
@@ -23,7 +23,6 @@
#![feature(unicode_internals)]
#![feature(step_trait)]
#![feature(slice_concat_ext)]
#![feature(try_from)]
#![feature(reverse_bits)]
#![feature(try_blocks)]
+3 -3
View File
@@ -466,14 +466,14 @@ fn description(&self) -> &str {
}
}
#[unstable(feature = "try_from", issue = "33417")]
#[stable(feature = "try_from", since = "1.34.0")]
impl Error for num::TryFromIntError {
fn description(&self) -> &str {
self.__description()
}
}
#[unstable(feature = "try_from", issue = "33417")]
#[stable(feature = "try_from", since = "1.34.0")]
impl Error for array::TryFromSliceError {
fn description(&self) -> &str {
self.__description()
@@ -548,7 +548,7 @@ fn description(&self) -> &str {
}
}
#[unstable(feature = "try_from", issue = "33417")]
#[stable(feature = "try_from", since = "1.34.0")]
impl Error for char::CharTryFromError {
fn description(&self) -> &str {
"converted integer out of range for `char`"
-1
View File
@@ -296,7 +296,6 @@
#![feature(str_internals)]
#![feature(thread_local)]
#![feature(toowned_clone_into)]
#![feature(try_from)]
#![feature(try_reserve)]
#![feature(unboxed_closures)]
#![feature(untagged_unions)]
+1 -2
View File
@@ -78,7 +78,6 @@
use ops::{self, Deref};
use rc::Rc;
use str::FromStr;
use string::ParseError;
use sync::Arc;
use ffi::{OsStr, OsString};
@@ -1533,7 +1532,7 @@ fn from(s: String) -> 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))
@@ -1,4 +1,3 @@
#![feature(try_from)]
#![allow(unused_must_use)]
use std::convert::TryFrom;
+3 -3
View File
@@ -4,9 +4,9 @@
// This test was added to show the motivation for doing this
// over `TryFrom` being blanket impl for all `T: From`
#![feature(try_from, never_type)]
#![feature(never_type)]
use std::convert::TryInto;
use std::convert::{TryInto, Infallible};
struct Foo<T> {
t: T,
@@ -32,6 +32,6 @@ fn into(self) -> Vec<T> {
}
pub fn main() {
let _: Result<Vec<i32>, !> = Foo { t: 10 }.try_into();
let _: Result<Vec<i32>, Infallible> = Foo { t: 10 }.try_into();
}
-1
View File
@@ -1,4 +1,3 @@
#![feature(try_from)]
use std::marker::PhantomData;
use std::convert::{TryFrom, AsRef};
+3 -3
View File
@@ -1,5 +1,5 @@
error[E0119]: conflicting implementations of trait `std::convert::AsRef<Q>` for type `std::boxed::Box<Q>`:
--> $DIR/conflict-with-std.rs:7:1
--> $DIR/conflict-with-std.rs:6:1
|
LL | impl AsRef<Q> for Box<Q> { //~ ERROR conflicting implementations
| ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -9,7 +9,7 @@ LL | impl AsRef<Q> for Box<Q> { //~ ERROR conflicting implementations
where T: ?Sized;
error[E0119]: conflicting implementations of trait `std::convert::From<S>` for type `S`:
--> $DIR/conflict-with-std.rs:14:1
--> $DIR/conflict-with-std.rs:13:1
|
LL | impl From<S> for S { //~ ERROR conflicting implementations
| ^^^^^^^^^^^^^^^^^^
@@ -18,7 +18,7 @@ LL | impl From<S> for S { //~ ERROR conflicting implementations
- impl<T> std::convert::From<T> for T;
error[E0119]: conflicting implementations of trait `std::convert::TryFrom<X>` for type `X`:
--> $DIR/conflict-with-std.rs:21:1
--> $DIR/conflict-with-std.rs:20:1
|
LL | impl TryFrom<X> for X { //~ ERROR conflicting implementations
| ^^^^^^^^^^^^^^^^^^^^^