Skip to content

Commit

Permalink
Rollup merge of rust-lang#71141 - Duddino:master, r=estebank
Browse files Browse the repository at this point in the history
Provide better compiler output when using `?` on `Option` in fn returning `Result` and vice-versa

Fixes rust-lang#71089
  • Loading branch information
Dylan-DPC authored Apr 16, 2020
2 parents c540bcc + fbc4168 commit 5a3b9db
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 1 deletion.
23 changes: 22 additions & 1 deletion src/librustc_trait_selection/traits/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
),
)
Expand All @@ -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()
Expand Down
13 changes: 13 additions & 0 deletions src/test/ui/option-to-result.rs
Original file line number Diff line number Diff line change
@@ -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)
}
29 changes: 29 additions & 0 deletions src/test/ui/option-to-result.stderr
Original file line number Diff line number Diff line change
@@ -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`.
4 changes: 4 additions & 0 deletions src/test/ui/try-on-option.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 5a3b9db

Please sign in to comment.