about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorDylan DPC <dylan.dpc@gmail.com>2020-04-16 16:34:27 +0200
committerGitHub <noreply@github.com>2020-04-16 16:34:27 +0200
commite4ec7965ef364e3860cb8d24a877d3e420f015b9 (patch)
tree403b48010ee018f523ca07c1b60cfd07a6c30538 /src
parent33500a2bbfec4482e0f149eafdeb9e111feeb5fc (diff)
parentfbc4168d809dae0408c2520ccfe585f564ad4a0b (diff)
downloadrust-e4ec7965ef364e3860cb8d24a877d3e420f015b9.tar.gz
rust-e4ec7965ef364e3860cb8d24a877d3e420f015b9.zip
Rollup merge of #71141 - Duddino:master, r=estebank
Provide better compiler output when using `?` on `Option` in fn returning `Result` and vice-versa

Fixes #71089
Diffstat (limited to 'src')
-rw-r--r--src/librustc_trait_selection/traits/error_reporting/mod.rs23
-rw-r--r--src/test/ui/option-to-result.rs13
-rw-r--r--src/test/ui/option-to-result.stderr29
-rw-r--r--src/test/ui/try-on-option.stderr4
4 files changed, 68 insertions, 1 deletions
diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs
index fef7adf0224..904720125d3 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<std::option::NoneError");
+                        let should_convert_result_to_option = format!("{}", trait_ref)
+                            .starts_with("<std::option::NoneError as std::convert::From<");
+                        if is_try && is_from && should_convert_option_to_result {
+                            err.span_suggestion_verbose(
+                                span.shrink_to_lo(),
+                                "consider converting the `Option<T>` into a `Result<T, _>` 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<T, _>` into an `Option<T>` using `Result::ok`",
+                                ".ok()".to_string(),
+                                Applicability::MachineApplicable,
+                            );
+                        }
+
                         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 00000000000..00e8b5244c5
--- /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<i32>{
+    let a:Result<i32, i32> = 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 00000000000..f673ef7fc1e
--- /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<std::option::NoneError>` 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<T>` into a `Result<T, _>` 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<i32>` 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<T, _>` into an `Option<T>` 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 07615b52a48..7a4bb75967b 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<T>` into a `Result<T, _>` 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