Skip to content

Commit e4ec796

Browse files
authored
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
2 parents 33500a2 + fbc4168 commit e4ec796

File tree

4 files changed

+68
-1
lines changed

4 files changed

+68
-1
lines changed

src/librustc_trait_selection/traits/error_reporting/mod.rs

+22-1
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
292292
)),
293293
Some(
294294
"the question mark operation (`?`) implicitly performs a \
295-
conversion on the error value using the `From` trait"
295+
conversion on the error value using the `From` trait"
296296
.to_owned(),
297297
),
298298
)
@@ -312,6 +312,27 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
312312
))
313313
);
314314

315+
let should_convert_option_to_result =
316+
format!("{}", trait_ref.print_only_trait_path())
317+
.starts_with("std::convert::From<std::option::NoneError");
318+
let should_convert_result_to_option = format!("{}", trait_ref)
319+
.starts_with("<std::option::NoneError as std::convert::From<");
320+
if is_try && is_from && should_convert_option_to_result {
321+
err.span_suggestion_verbose(
322+
span.shrink_to_lo(),
323+
"consider converting the `Option<T>` into a `Result<T, _>` using `Option::ok_or` or `Option::ok_or_else`",
324+
".ok_or_else(|| /* error value */)".to_string(),
325+
Applicability::HasPlaceholders,
326+
);
327+
} else if is_try && is_from && should_convert_result_to_option {
328+
err.span_suggestion_verbose(
329+
span.shrink_to_lo(),
330+
"consider converting the `Result<T, _>` into an `Option<T>` using `Result::ok`",
331+
".ok()".to_string(),
332+
Applicability::MachineApplicable,
333+
);
334+
}
335+
315336
let explanation =
316337
if obligation.cause.code == ObligationCauseCode::MainFunctionType {
317338
"consider using `()`, or a `Result`".to_owned()

src/test/ui/option-to-result.rs

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
fn main(){ }
2+
3+
fn test_result() -> Result<(),()> {
4+
let a:Option<()> = Some(());
5+
a?;//~ ERROR `?` couldn't convert the error
6+
Ok(())
7+
}
8+
9+
fn test_option() -> Option<i32>{
10+
let a:Result<i32, i32> = Ok(5);
11+
a?;//~ ERROR `?` couldn't convert the error
12+
Some(5)
13+
}

src/test/ui/option-to-result.stderr

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
error[E0277]: `?` couldn't convert the error to `()`
2+
--> $DIR/option-to-result.rs:5:6
3+
|
4+
LL | a?;
5+
| ^ the trait `std::convert::From<std::option::NoneError>` is not implemented for `()`
6+
|
7+
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
8+
= note: required by `std::convert::From::from`
9+
help: consider converting the `Option<T>` into a `Result<T, _>` using `Option::ok_or` or `Option::ok_or_else`
10+
|
11+
LL | a.ok_or_else(|| /* error value */)?;
12+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
13+
14+
error[E0277]: `?` couldn't convert the error to `std::option::NoneError`
15+
--> $DIR/option-to-result.rs:11:6
16+
|
17+
LL | a?;
18+
| ^ the trait `std::convert::From<i32>` is not implemented for `std::option::NoneError`
19+
|
20+
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
21+
= note: required by `std::convert::From::from`
22+
help: consider converting the `Result<T, _>` into an `Option<T>` using `Result::ok`
23+
|
24+
LL | a.ok()?;
25+
| ^^^^^
26+
27+
error: aborting due to 2 previous errors
28+
29+
For more information about this error, try `rustc --explain E0277`.

src/test/ui/try-on-option.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ LL | x?;
66
|
77
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
88
= note: required by `std::convert::From::from`
9+
help: consider converting the `Option<T>` into a `Result<T, _>` using `Option::ok_or` or `Option::ok_or_else`
10+
|
11+
LL | x.ok_or_else(|| /* error value */)?;
12+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
913

1014
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
1115
--> $DIR/try-on-option.rs:13:5

0 commit comments

Comments
 (0)