From ce994b633d9143dd00140c64fe53194a2927dff1 Mon Sep 17 00:00:00 2001 From: Duddino Date: Tue, 14 Apr 2020 17:31:59 +0200 Subject: [PATCH 1/2] Provide better compiler output when using `?` on `Option` in fn returning `Result` and vice-versa --- .../traits/error_reporting/mod.rs | 23 ++++++++++++++- src/test/ui/option-to-result.rs | 13 +++++++++ src/test/ui/option-to-result.stderr | 29 +++++++++++++++++++ src/test/ui/try-on-option.stderr | 4 +++ 4 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/option-to-result.rs create mode 100644 src/test/ui/option-to-result.stderr diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index fef7adf02246b..a77ea33bcde09 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -292,7 +292,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { )), Some( "the question mark operation (`?`) implicitly performs a \ - conversion on the error value using the `From` trait" + conversion on the error value using the `From` trait" .to_owned(), ), ) @@ -312,6 +312,27 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { )) ); + let should_convert_option_to_result = + format!("{}", trait_ref.print_only_trait_path()) + .starts_with("std::convert::From` into a `Result` using `Option::ok_or` or `Option::ok_or_else`", + ".ok_or_else(|_| /* error value */)".to_string(), + Applicability::HasPlaceholders, + ); + } else if is_try && is_from && should_convert_result_to_option { + err.span_suggestion_verbose( + span.shrink_to_lo(), + "consider converting the `Result` into an `Option` using `Result::ok`", + ".ok()".to_string(), + Applicability::HasPlaceholders, + ); + } + let explanation = if obligation.cause.code == ObligationCauseCode::MainFunctionType { "consider using `()`, or a `Result`".to_owned() diff --git a/src/test/ui/option-to-result.rs b/src/test/ui/option-to-result.rs new file mode 100644 index 0000000000000..00e8b5244c54a --- /dev/null +++ b/src/test/ui/option-to-result.rs @@ -0,0 +1,13 @@ +fn main(){ } + +fn test_result() -> Result<(),()> { + let a:Option<()> = Some(()); + a?;//~ ERROR `?` couldn't convert the error + Ok(()) +} + +fn test_option() -> Option{ + let a:Result = Ok(5); + a?;//~ ERROR `?` couldn't convert the error + Some(5) +} diff --git a/src/test/ui/option-to-result.stderr b/src/test/ui/option-to-result.stderr new file mode 100644 index 0000000000000..3c51bcece570b --- /dev/null +++ b/src/test/ui/option-to-result.stderr @@ -0,0 +1,29 @@ +error[E0277]: `?` couldn't convert the error to `()` + --> $DIR/option-to-result.rs:5:6 + | +LL | a?; + | ^ the trait `std::convert::From` is not implemented for `()` + | + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + = note: required by `std::convert::From::from` +help: consider converting the `Option` into a `Result` using `Option::ok_or` or `Option::ok_or_else` + | +LL | a.ok_or_else(|_| /* error value */)?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `?` couldn't convert the error to `std::option::NoneError` + --> $DIR/option-to-result.rs:11:6 + | +LL | a?; + | ^ the trait `std::convert::From` is not implemented for `std::option::NoneError` + | + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + = note: required by `std::convert::From::from` +help: consider converting the `Result` into an `Option` using `Result::ok` + | +LL | a.ok()?; + | ^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/try-on-option.stderr b/src/test/ui/try-on-option.stderr index 07615b52a48a5..d1c0276a67ad2 100644 --- a/src/test/ui/try-on-option.stderr +++ b/src/test/ui/try-on-option.stderr @@ -6,6 +6,10 @@ LL | x?; | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = note: required by `std::convert::From::from` +help: consider converting the `Option` into a `Result` using `Option::ok_or` or `Option::ok_or_else` + | +LL | x.ok_or_else(|_| /* error value */)?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) --> $DIR/try-on-option.rs:13:5 From fbc4168d809dae0408c2520ccfe585f564ad4a0b Mon Sep 17 00:00:00 2001 From: Duddino Date: Wed, 15 Apr 2020 10:57:22 +0200 Subject: [PATCH 2/2] Provide better compiler output when using `?` on `Option` in fn returning `Result` and vice-versa --- src/librustc_trait_selection/traits/error_reporting/mod.rs | 4 ++-- src/test/ui/option-to-result.stderr | 4 ++-- src/test/ui/try-on-option.stderr | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index a77ea33bcde09..904720125d3d7 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -321,7 +321,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.span_suggestion_verbose( span.shrink_to_lo(), "consider converting the `Option` into a `Result` using `Option::ok_or` or `Option::ok_or_else`", - ".ok_or_else(|_| /* error value */)".to_string(), + ".ok_or_else(|| /* error value */)".to_string(), Applicability::HasPlaceholders, ); } else if is_try && is_from && should_convert_result_to_option { @@ -329,7 +329,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { span.shrink_to_lo(), "consider converting the `Result` into an `Option` using `Result::ok`", ".ok()".to_string(), - Applicability::HasPlaceholders, + Applicability::MachineApplicable, ); } diff --git a/src/test/ui/option-to-result.stderr b/src/test/ui/option-to-result.stderr index 3c51bcece570b..f673ef7fc1e69 100644 --- a/src/test/ui/option-to-result.stderr +++ b/src/test/ui/option-to-result.stderr @@ -8,8 +8,8 @@ LL | a?; = note: required by `std::convert::From::from` help: consider converting the `Option` into a `Result` using `Option::ok_or` or `Option::ok_or_else` | -LL | a.ok_or_else(|_| /* error value */)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | a.ok_or_else(|| /* error value */)?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `?` couldn't convert the error to `std::option::NoneError` --> $DIR/option-to-result.rs:11:6 diff --git a/src/test/ui/try-on-option.stderr b/src/test/ui/try-on-option.stderr index d1c0276a67ad2..7a4bb75967b1f 100644 --- a/src/test/ui/try-on-option.stderr +++ b/src/test/ui/try-on-option.stderr @@ -8,8 +8,8 @@ LL | x?; = note: required by `std::convert::From::from` help: consider converting the `Option` into a `Result` using `Option::ok_or` or `Option::ok_or_else` | -LL | x.ok_or_else(|_| /* error value */)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | x.ok_or_else(|| /* error value */)?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) --> $DIR/try-on-option.rs:13:5