From 4c2e3144a98f7a636fd6a33fce122121431ad9b4 Mon Sep 17 00:00:00 2001 From: Brad Gibson Date: Thu, 26 Apr 2018 16:29:22 -0700 Subject: [PATCH 1/9] added DerefOption and DerefResult + tests to std --- src/libcore/option.rs | 21 +++++++++++-- src/libcore/result.rs | 59 ++++++++++++++++++++++++++++++++++++- src/libcore/tests/option.rs | 11 +++++++ src/libcore/tests/result.rs | 21 +++++++++++++ 4 files changed, 109 insertions(+), 3 deletions(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 0dfdabee03182..c3ef619d739c0 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -146,7 +146,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use iter::{FromIterator, FusedIterator, TrustedLen}; -use {mem, ops}; +use {mem, ops::{self, Deref}}; // Note that this is not a lang item per se, but it has a hidden dependency on // `Iterator`, which is one. The compiler assumes that the `next` method of @@ -914,7 +914,6 @@ fn expect_failed(msg: &str) -> ! { panic!("{}", msg) } - ///////////////////////////////////////////////////////////////////////////// // Trait implementations ///////////////////////////////////////////////////////////////////////////// @@ -979,6 +978,24 @@ impl From for Option { } } +#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +/// Extension trait to get a reference of an Option via the Deref trait. +pub trait OptionDeref { + /// Converts from `&Option` to `Option<&T::Target>`. + /// + /// Leaves the original Option in-place, creating a new one with a reference + /// to the original one, additionally coercing the contents via `Deref`. + fn deref(&self) -> Option<&T::Target>; +} + +#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +impl OptionDeref for Option +{ + fn deref(&self) -> Option<&T::Target> { + self.as_ref().map(|t| t.deref()) + } +} + ///////////////////////////////////////////////////////////////////////////// // The Option Iterators ///////////////////////////////////////////////////////////////////////////// diff --git a/src/libcore/result.rs b/src/libcore/result.rs index c152d4979b90e..9877a2001a0ff 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -242,7 +242,7 @@ use fmt; use iter::{FromIterator, FusedIterator, TrustedLen}; -use ops; +use ops::{self, Deref}; /// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]). /// @@ -999,6 +999,63 @@ impl<'a, T, E> IntoIterator for &'a mut Result { } } +#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +/// Extension trait to get a reference to a Result via the Deref trait. +pub trait ResultDeref { + /// Converts from `&Result` to `Result<&T::Target, &E>`. + /// + /// Leaves the original Result in-place, creating a new one with a reference + /// to the original one, additionally coercing the `Ok` arm of the Result via + /// `Deref`. + fn deref_ok(&self) -> Result<&T::Target, &E> + where + T: Deref; + + /// Converts from `&Result` to `Result<&T, &E::Target>`. + /// + /// Leaves the original Result in-place, creating a new one with a reference + /// to the original one, additionally coercing the `Err` arm of the Result via + /// `Deref`. + fn deref_err(&self) -> Result<&T, &E::Target> + where + E: Deref; + + /// Converts from `&Result` to `Result<&T::Target, &E::Target>`. + /// + /// Leaves the original Result in-place, creating a new one with a reference + /// to the original one, additionally coercing both the `Ok` and `Err` arms + /// of the Result via `Deref`. + fn deref(&self) -> Result<&T::Target, &E::Target> + where + T: Deref, + E: Deref; +} + +#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +impl ResultDeref for Result { + fn deref_ok(&self) -> Result<&T::Target, &E> + where + T: Deref, + { + self.as_ref().map(|t| t.deref()) + } + + fn deref_err(&self) -> Result<&T, &E::Target> + where + E: Deref, + { + self.as_ref().map_err(|e| e.deref()) + } + + fn deref(&self) -> Result<&T::Target, &E::Target> + where + T: Deref, + E: Deref, + { + self.as_ref().map(|t| t.deref()).map_err(|e| e.deref()) + } +} + ///////////////////////////////////////////////////////////////////////////// // The Result Iterators ///////////////////////////////////////////////////////////////////////////// diff --git a/src/libcore/tests/option.rs b/src/libcore/tests/option.rs index 22109e28edd9b..77d550c532a34 100644 --- a/src/libcore/tests/option.rs +++ b/src/libcore/tests/option.rs @@ -297,3 +297,14 @@ fn test_try() { } assert_eq!(try_option_err(), Err(NoneError)); } + +#[test] +fn test_option_deref() { + // Some: &Option::Some(T) -> Option<&T::Deref::Target>::Some(&*T) + let ref_option = &Some(&42); + assert_eq!(ref_option.deref(), Some(&42)); + + // None: &Option>::None -> None + let ref_option = &None; + assert_eq!(ref_option.deref(), None); +} diff --git a/src/libcore/tests/result.rs b/src/libcore/tests/result.rs index ce41bde8342ed..dd23467322dc9 100644 --- a/src/libcore/tests/result.rs +++ b/src/libcore/tests/result.rs @@ -231,3 +231,24 @@ fn test_try() { } assert_eq!(try_result_err(), Err(1)); } + +#[test] +fn test_result_deref() { + // Ok(T).deref_ok() -> Result<&T, &E::Deref::Target>::Ok(&T) + let ref_ok: &Result<&i32, &u8> = &Ok(&42); + assert_eq!(ref_ok.deref_ok(), Ok(&42)); + assert_eq!(ref_ok.deref_ok(), Ok(&42)); + assert_eq!(ref_ok.deref(), Ok(&42)); + + // Err(E) -> Result<&T, &E::Deref::Target>::Err(&*E) + let ref_err: &Result<&i32, &u8> = &Err(&41); + assert_eq!(ref_err.deref_err(), Err(&41)); + assert_eq!(ref_err.deref_err(), Err(&41)); + assert_eq!(ref_err.deref(), Err(&41)); + + // &Ok(T).deref_err() -> Result<&T, &E::Deref::Target>::Ok(&T) + assert_eq!(ref_ok.deref_err(), Ok(&&42)); + + // &Err(E) -> Result<&T::Deref::Target, &E>::Err(&E) + assert_eq!(ref_err.deref_ok(), Err(&&41)); +} From 6c7ea4ca9b92e527873115951cfc8c864bbb71ad Mon Sep 17 00:00:00 2001 From: Brad Gibson Date: Thu, 26 Apr 2018 19:54:24 -0700 Subject: [PATCH 2/9] refactored to implement without trait --- src/libcore/option.rs | 29 ++++++-------- src/libcore/result.rs | 91 ++++++++++++++++--------------------------- 2 files changed, 45 insertions(+), 75 deletions(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index c3ef619d739c0..506e54ba5e4e6 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -878,6 +878,17 @@ impl Option { } } +# [unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +impl Option { + /// Converts from `&Option` to `Option<&T::Target>`. + /// + /// Leaves the original Option in-place, creating a new one with a reference + /// to the original one, additionally coercing the contents via `Deref`. + pub fn deref(&self) -> Option<&T::Target> { + self.as_ref().map(|t| t.deref()) + } +} + impl Option> { /// Transposes an `Option` of a `Result` into a `Result` of an `Option`. /// @@ -978,24 +989,6 @@ impl From for Option { } } -#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] -/// Extension trait to get a reference of an Option via the Deref trait. -pub trait OptionDeref { - /// Converts from `&Option` to `Option<&T::Target>`. - /// - /// Leaves the original Option in-place, creating a new one with a reference - /// to the original one, additionally coercing the contents via `Deref`. - fn deref(&self) -> Option<&T::Target>; -} - -#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] -impl OptionDeref for Option -{ - fn deref(&self) -> Option<&T::Target> { - self.as_ref().map(|t| t.deref()) - } -} - ///////////////////////////////////////////////////////////////////////////// // The Option Iterators ///////////////////////////////////////////////////////////////////////////// diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 9877a2001a0ff..fbf2035e83f46 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -909,6 +909,40 @@ impl Result { } } +impl Result { + #[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] + /// Converts from `&Result` to `Result<&T::Target, &E>`. + /// + /// Leaves the original Result in-place, creating a new one with a reference + /// to the original one, additionally coercing the `Ok` arm of the Result via + /// `Deref`. + pub fn deref_ok(&self) -> Result<&T::Target, &E> { + self.as_ref().map(|t| t.deref()) + } + + #[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] + /// Converts from `&Result` to `Result<&T, &E::Target>`. + /// + /// Leaves the original Result in-place, creating a new one with a reference + /// to the original one, additionally coercing the `Err` arm of the Result via + /// `Deref`. + pub fn deref_err(&self) -> Result<&T, &E::Target> + { + self.as_ref().map_err(|e| e.deref()) + } + + #[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] + /// Converts from `&Result` to `Result<&T::Target, &E::Target>`. + /// + /// Leaves the original Result in-place, creating a new one with a reference + /// to the original one, additionally coercing both the `Ok` and `Err` arms + /// of the Result via `Deref`. + pub fn deref(&self) -> Result<&T::Target, &E::Target> + { + self.as_ref().map(|t| t.deref()).map_err(|e| e.deref()) + } +} + impl Result, E> { /// Transposes a `Result` of an `Option` into an `Option` of a `Result`. /// @@ -999,63 +1033,6 @@ impl<'a, T, E> IntoIterator for &'a mut Result { } } -#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] -/// Extension trait to get a reference to a Result via the Deref trait. -pub trait ResultDeref { - /// Converts from `&Result` to `Result<&T::Target, &E>`. - /// - /// Leaves the original Result in-place, creating a new one with a reference - /// to the original one, additionally coercing the `Ok` arm of the Result via - /// `Deref`. - fn deref_ok(&self) -> Result<&T::Target, &E> - where - T: Deref; - - /// Converts from `&Result` to `Result<&T, &E::Target>`. - /// - /// Leaves the original Result in-place, creating a new one with a reference - /// to the original one, additionally coercing the `Err` arm of the Result via - /// `Deref`. - fn deref_err(&self) -> Result<&T, &E::Target> - where - E: Deref; - - /// Converts from `&Result` to `Result<&T::Target, &E::Target>`. - /// - /// Leaves the original Result in-place, creating a new one with a reference - /// to the original one, additionally coercing both the `Ok` and `Err` arms - /// of the Result via `Deref`. - fn deref(&self) -> Result<&T::Target, &E::Target> - where - T: Deref, - E: Deref; -} - -#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] -impl ResultDeref for Result { - fn deref_ok(&self) -> Result<&T::Target, &E> - where - T: Deref, - { - self.as_ref().map(|t| t.deref()) - } - - fn deref_err(&self) -> Result<&T, &E::Target> - where - E: Deref, - { - self.as_ref().map_err(|e| e.deref()) - } - - fn deref(&self) -> Result<&T::Target, &E::Target> - where - T: Deref, - E: Deref, - { - self.as_ref().map(|t| t.deref()).map_err(|e| e.deref()) - } -} - ///////////////////////////////////////////////////////////////////////////// // The Result Iterators ///////////////////////////////////////////////////////////////////////////// From 527e84f300a2cc36b74dcfc6a23ea9352cbf2e0b Mon Sep 17 00:00:00 2001 From: Brad Gibson Date: Thu, 26 Apr 2018 20:41:10 -0700 Subject: [PATCH 3/9] cleaned up #[unstable] attributes --- src/libcore/result.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libcore/result.rs b/src/libcore/result.rs index fbf2035e83f46..9e302cb9f968e 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -909,8 +909,8 @@ impl Result { } } +#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] impl Result { - #[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] /// Converts from `&Result` to `Result<&T::Target, &E>`. /// /// Leaves the original Result in-place, creating a new one with a reference @@ -920,7 +920,6 @@ impl Result { self.as_ref().map(|t| t.deref()) } - #[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] /// Converts from `&Result` to `Result<&T, &E::Target>`. /// /// Leaves the original Result in-place, creating a new one with a reference @@ -931,7 +930,6 @@ impl Result { self.as_ref().map_err(|e| e.deref()) } - #[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] /// Converts from `&Result` to `Result<&T::Target, &E::Target>`. /// /// Leaves the original Result in-place, creating a new one with a reference From b812d44a01bbc7180c11c9fdc3de3926105cbe05 Mon Sep 17 00:00:00 2001 From: Brad Gibson Date: Thu, 26 Apr 2018 20:42:44 -0700 Subject: [PATCH 4/9] added #![feature(inner_deref)] to enable inner_deref-related unit tests --- src/libcore/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 0e21a3327fddf..55c5e1e7971d4 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -103,6 +103,7 @@ #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(doc_alias)] +#![feature(inner_deref)] #![cfg_attr(not(stage0), feature(mmx_target_feature))] #![cfg_attr(not(stage0), feature(tbm_target_feature))] From 2bf9fbc8d61e2283cd6133b96cff2e04988bbe69 Mon Sep 17 00:00:00 2001 From: Brad Gibson Date: Fri, 27 Apr 2018 06:36:37 -0700 Subject: [PATCH 5/9] separated inner_deref Result impls --- src/libcore/result.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 9e302cb9f968e..c545064aadb29 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -910,7 +910,7 @@ impl Result { } #[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] -impl Result { +impl Result { /// Converts from `&Result` to `Result<&T::Target, &E>`. /// /// Leaves the original Result in-place, creating a new one with a reference @@ -919,7 +919,10 @@ impl Result { pub fn deref_ok(&self) -> Result<&T::Target, &E> { self.as_ref().map(|t| t.deref()) } +} +#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +impl Result { /// Converts from `&Result` to `Result<&T, &E::Target>`. /// /// Leaves the original Result in-place, creating a new one with a reference @@ -929,7 +932,10 @@ impl Result { { self.as_ref().map_err(|e| e.deref()) } +} +#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +impl Result { /// Converts from `&Result` to `Result<&T::Target, &E::Target>`. /// /// Leaves the original Result in-place, creating a new one with a reference From 8aa049e54be521c3826b0af15a87b3b4db1fb77b Mon Sep 17 00:00:00 2001 From: Brad Gibson Date: Fri, 27 Apr 2018 06:39:04 -0700 Subject: [PATCH 6/9] moved #![feature(inner_deref) to from libcore crate to libcore tests crate to enable related tests --- src/libcore/lib.rs | 1 - src/libcore/tests/lib.rs | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 55c5e1e7971d4..0e21a3327fddf 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -103,7 +103,6 @@ #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(doc_alias)] -#![feature(inner_deref)] #![cfg_attr(not(stage0), feature(mmx_target_feature))] #![cfg_attr(not(stage0), feature(tbm_target_feature))] diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index e4d277179382f..111cf58c2c69d 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -46,6 +46,7 @@ #![feature(reverse_bits)] #![feature(inclusive_range_fields)] #![feature(iterator_find_map)] +#![feature(inner_deref)] extern crate core; extern crate test; From 17124488c7c7582fb9ab22ed87b2759ee20a4602 Mon Sep 17 00:00:00 2001 From: Brad Gibson Date: Fri, 27 Apr 2018 07:07:26 -0700 Subject: [PATCH 7/9] fixed inner_deref test case for None --- src/libcore/tests/option.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/tests/option.rs b/src/libcore/tests/option.rs index 77d550c532a34..e7e48b2daa2e2 100644 --- a/src/libcore/tests/option.rs +++ b/src/libcore/tests/option.rs @@ -305,6 +305,6 @@ fn test_option_deref() { assert_eq!(ref_option.deref(), Some(&42)); // None: &Option>::None -> None - let ref_option = &None; + let ref_option: &Option<&i32> = &None; assert_eq!(ref_option.deref(), None); } From c025fdebbada2757deccdd97219ff0313631f2ed Mon Sep 17 00:00:00 2001 From: Brad Gibson Date: Mon, 30 Apr 2018 12:51:43 -0700 Subject: [PATCH 8/9] fixed some and added more tests --- src/libcore/option.rs | 2 +- src/libcore/tests/option.rs | 8 ++ src/libcore/tests/result.rs | 102 +++++++++++++++--- .../option_deref.rs | 16 +++ .../result_deref.rs | 16 +++ .../result_deref_err.rs | 16 +++ .../result_deref_ok.rs | 16 +++ 7 files changed, 158 insertions(+), 18 deletions(-) create mode 100644 src/test/compile-fail/issue-50264-inner-deref-trait/option_deref.rs create mode 100644 src/test/compile-fail/issue-50264-inner-deref-trait/result_deref.rs create mode 100644 src/test/compile-fail/issue-50264-inner-deref-trait/result_deref_err.rs create mode 100644 src/test/compile-fail/issue-50264-inner-deref-trait/result_deref_ok.rs diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 506e54ba5e4e6..deb0380171c4e 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -878,7 +878,7 @@ impl Option { } } -# [unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] +#[unstable(feature = "inner_deref", reason = "newly added", issue = "50264")] impl Option { /// Converts from `&Option` to `Option<&T::Target>`. /// diff --git a/src/libcore/tests/option.rs b/src/libcore/tests/option.rs index e7e48b2daa2e2..ced7b03636a09 100644 --- a/src/libcore/tests/option.rs +++ b/src/libcore/tests/option.rs @@ -304,7 +304,15 @@ fn test_option_deref() { let ref_option = &Some(&42); assert_eq!(ref_option.deref(), Some(&42)); + let ref_option = &Some(String::from("a result")); + assert_eq!(ref_option.deref(), Some("a result")); + + let ref_option = &Some(vec![1, 2, 3, 4, 5]); + assert_eq!(ref_option.deref(), Some(&[1, 2, 3, 4, 5][..])); + // None: &Option>::None -> None let ref_option: &Option<&i32> = &None; assert_eq!(ref_option.deref(), None); + + } diff --git a/src/libcore/tests/result.rs b/src/libcore/tests/result.rs index dd23467322dc9..fd0dd21401b88 100644 --- a/src/libcore/tests/result.rs +++ b/src/libcore/tests/result.rs @@ -234,21 +234,89 @@ fn test_try() { #[test] fn test_result_deref() { - // Ok(T).deref_ok() -> Result<&T, &E::Deref::Target>::Ok(&T) - let ref_ok: &Result<&i32, &u8> = &Ok(&42); - assert_eq!(ref_ok.deref_ok(), Ok(&42)); - assert_eq!(ref_ok.deref_ok(), Ok(&42)); - assert_eq!(ref_ok.deref(), Ok(&42)); - - // Err(E) -> Result<&T, &E::Deref::Target>::Err(&*E) - let ref_err: &Result<&i32, &u8> = &Err(&41); - assert_eq!(ref_err.deref_err(), Err(&41)); - assert_eq!(ref_err.deref_err(), Err(&41)); - assert_eq!(ref_err.deref(), Err(&41)); - - // &Ok(T).deref_err() -> Result<&T, &E::Deref::Target>::Ok(&T) - assert_eq!(ref_ok.deref_err(), Ok(&&42)); - - // &Err(E) -> Result<&T::Deref::Target, &E>::Err(&E) - assert_eq!(ref_err.deref_ok(), Err(&&41)); + // &Result::Ok(T).deref_ok() -> + // Result<&T::Deref::Target, &E>::Ok(&*T) + let ref_ok = &Result::Ok::<&i32, u8>(&42); + let expected_result = Result::Ok::<&i32, &u8>(&42); + assert_eq!(ref_ok.deref_ok(), expected_result); + + let ref_ok = &Result::Ok::(String::from("a result")); + let expected_result = Result::Ok::<&str, &u32>("a result"); + assert_eq!(ref_ok.deref_ok(), expected_result); + + let ref_ok = &Result::Ok::, u32>(vec![1, 2, 3, 4, 5]); + let expected_result = Result::Ok::<&[i32], &u32>(&[1, 2, 3, 4, 5][..]); + assert_eq!(ref_ok.deref_ok(), expected_result); + + // &Result::Ok(T).deref() -> + // Result<&T::Deref::Target, &E::Deref::Target>::Ok(&*T) + let ref_ok = &Result::Ok::<&i32, &u8>(&42); + let expected_result = Result::Ok::<&i32, &u8>(&42); + assert_eq!(ref_ok.deref(), expected_result); + + let ref_ok = &Result::Ok::(String::from("a result")); + let expected_result = Result::Ok::<&str, &u32>("a result"); + assert_eq!(ref_ok.deref(), expected_result); + + let ref_ok = &Result::Ok::, &u32>(vec![1, 2, 3, 4, 5]); + let expected_result = Result::Ok::<&[i32], &u32>(&[1, 2, 3, 4, 5][..]); + assert_eq!(ref_ok.deref(), expected_result); + + // &Result::Err(T).deref_err() -> + // Result<&T, &E::Deref::Target>::Err(&*E) + let ref_err = &Result::Err::(&41); + let expected_result = Result::Err::<&u8, &i32>(&41); + assert_eq!(ref_err.deref_err(), expected_result); + + let ref_err = &Result::Err::(String::from("an error")); + let expected_result = Result::Err::<&u32, &str>("an error"); + assert_eq!(ref_err.deref_err(), expected_result); + + let ref_err = &Result::Err::>(vec![5, 4, 3, 2, 1]); + let expected_result = Result::Err::<&u32, &[i32]>(&[5, 4, 3, 2, 1][..]); + assert_eq!(ref_err.deref_err(), expected_result); + + // &Result::Err(T).deref_err() -> + // Result<&T, &E::Deref::Target>::Err(&*E) + let ref_err = &Result::Err::<&u8, &i32>(&41); + let expected_result = Result::Err::<&u8, &i32>(&41); + assert_eq!(ref_err.deref(), expected_result); + + let ref_err = &Result::Err::<&u32, String>(String::from("an error")); + let expected_result = Result::Err::<&u32, &str>("an error"); + assert_eq!(ref_err.deref(), expected_result); + + let ref_err = &Result::Err::<&u32, Vec>(vec![5, 4, 3, 2, 1]); + let expected_result = Result::Err::<&u32, &[i32]>(&[5, 4, 3, 2, 1][..]); + assert_eq!(ref_err.deref(), expected_result); + + // *Odd corner cases (tested for completeness)* + + // &Result::Ok(T).deref_err() -> + // Result<&T, &E::Deref::Target>::Ok(&T) + let ref_ok = &Result::Ok::(42); + let expected_result = Result::Ok::<&i32, &u8>(&42); + assert_eq!(ref_ok.deref_err(), expected_result); + + let ref_ok = &Result::Ok::<&str, &u32>("a result"); + let expected_result = Result::Ok::<&&str, &u32>(&"a result"); + assert_eq!(ref_ok.deref_err(), expected_result); + + let ref_ok = &Result::Ok::<[i32; 5], &u32>([1, 2, 3, 4, 5]); + let expected_result = Result::Ok::<&[i32; 5], &u32>(&[1, 2, 3, 4, 5]); + assert_eq!(ref_ok.deref_err(), expected_result); + + // &Result::Err(E).deref_ok() -> + // Result<&T::Deref::Target, &E>::Err(&E) + let ref_err = &Result::Err::<&u8, i32>(41); + let expected_result = Result::Err::<&u8, &i32>(&41); + assert_eq!(ref_err.deref_ok(), expected_result); + + let ref_err = &Result::Err::<&u32, &str>("an error"); + let expected_result = Result::Err::<&u32, &&str>(&"an error"); + assert_eq!(ref_err.deref_ok(), expected_result); + + let ref_err = &Result::Err::<&u32, [i32; 5]>([5, 4, 3, 2, 1]); + let expected_result = Result::Err::<&u32, &[i32; 5]>(&[5, 4, 3, 2, 1]); + assert_eq!(ref_err.deref_ok(), expected_result); } diff --git a/src/test/compile-fail/issue-50264-inner-deref-trait/option_deref.rs b/src/test/compile-fail/issue-50264-inner-deref-trait/option_deref.rs new file mode 100644 index 0000000000000..4c67fb3bef103 --- /dev/null +++ b/src/test/compile-fail/issue-50264-inner-deref-trait/option_deref.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(inner_deref)] + +fn main() { + let _result = &Some(42).deref(); +//~^ ERROR no method named `deref` found for type `std::option::Option<{integer}>` +} diff --git a/src/test/compile-fail/issue-50264-inner-deref-trait/result_deref.rs b/src/test/compile-fail/issue-50264-inner-deref-trait/result_deref.rs new file mode 100644 index 0000000000000..73bdf0b920907 --- /dev/null +++ b/src/test/compile-fail/issue-50264-inner-deref-trait/result_deref.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(inner_deref)] + +fn main() { + let _result = &Ok(42).deref(); +//~^ ERROR no method named `deref` found +} diff --git a/src/test/compile-fail/issue-50264-inner-deref-trait/result_deref_err.rs b/src/test/compile-fail/issue-50264-inner-deref-trait/result_deref_err.rs new file mode 100644 index 0000000000000..5d1e7472d8f18 --- /dev/null +++ b/src/test/compile-fail/issue-50264-inner-deref-trait/result_deref_err.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(inner_deref)] + +fn main() { + let _result = &Err(41).deref_err(); +//~^ ERROR no method named `deref_err` found +} diff --git a/src/test/compile-fail/issue-50264-inner-deref-trait/result_deref_ok.rs b/src/test/compile-fail/issue-50264-inner-deref-trait/result_deref_ok.rs new file mode 100644 index 0000000000000..bee8e0c062bae --- /dev/null +++ b/src/test/compile-fail/issue-50264-inner-deref-trait/result_deref_ok.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(inner_deref)] + +fn main() { + let _result = &Ok(42).deref_ok(); +//~^ ERROR no method named `deref_ok` found +} From e1d5509bf381d978a1894b6ba869c3b56dd3eeca Mon Sep 17 00:00:00 2001 From: Brad Gibson Date: Wed, 2 May 2018 19:16:29 -0700 Subject: [PATCH 9/9] Added comments providing justification for support of calling deref_* with wrong variant --- src/libcore/tests/result.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libcore/tests/result.rs b/src/libcore/tests/result.rs index fd0dd21401b88..f8b5ea5e16e48 100644 --- a/src/libcore/tests/result.rs +++ b/src/libcore/tests/result.rs @@ -290,7 +290,11 @@ fn test_result_deref() { let expected_result = Result::Err::<&u32, &[i32]>(&[5, 4, 3, 2, 1][..]); assert_eq!(ref_err.deref(), expected_result); - // *Odd corner cases (tested for completeness)* + // The following cases test calling deref_* with the wrong variant (i.e. + // `deref_ok()` with a `Result::Err()`, or `deref_err()` with a `Result::Ok()`. + // While unusual, these cases are supported to ensure that an `inner_deref` + // call can still be made even when one of the Result types does not implement + // `Deref` (for example, std::io::Error). // &Result::Ok(T).deref_err() -> // Result<&T, &E::Deref::Target>::Ok(&T)