Skip to content

Commit be90f90

Browse files
committed
Point at the return type on .into() failure caused by ?
Fix #35946.
1 parent 8ce3f84 commit be90f90

File tree

5 files changed

+48
-14
lines changed

5 files changed

+48
-14
lines changed

src/librustc_trait_selection/traits/error_reporting/mod.rs

+24-14
Original file line numberDiff line numberDiff line change
@@ -317,20 +317,30 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
317317
.starts_with("std::convert::From<std::option::NoneError");
318318
let should_convert_result_to_option = format!("{}", trait_ref)
319319
.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-
);
320+
if is_try && is_from {
321+
if should_convert_option_to_result {
322+
err.span_suggestion_verbose(
323+
span.shrink_to_lo(),
324+
"consider converting the `Option<T>` into a `Result<T, _>` \
325+
using `Option::ok_or` or `Option::ok_or_else`",
326+
".ok_or_else(|| /* error value */)".to_string(),
327+
Applicability::HasPlaceholders,
328+
);
329+
} else if should_convert_result_to_option {
330+
err.span_suggestion_verbose(
331+
span.shrink_to_lo(),
332+
"consider converting the `Result<T, _>` into an `Option<T>` \
333+
using `Result::ok`",
334+
".ok()".to_string(),
335+
Applicability::MachineApplicable,
336+
);
337+
}
338+
if let Some(ret_span) = self.return_type_span(obligation) {
339+
err.span_label(
340+
ret_span,
341+
&format!("expected `{}` because of this", trait_ref.self_ty()),
342+
);
343+
}
334344
}
335345

336346
let explanation =

src/librustc_trait_selection/traits/error_reporting/suggestions.rs

+13
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ pub trait InferCtxtExt<'tcx> {
8484
trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
8585
);
8686

87+
fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span>;
88+
8789
fn suggest_impl_trait(
8890
&self,
8991
err: &mut DiagnosticBuilder<'tcx>,
@@ -760,6 +762,17 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
760762
}
761763
}
762764

765+
fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span> {
766+
let hir = self.tcx.hir();
767+
let parent_node = hir.get_parent_node(obligation.cause.body_id);
768+
let sig = match hir.find(parent_node) {
769+
Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. })) => sig,
770+
_ => return None,
771+
};
772+
773+
if let hir::FnRetTy::Return(ret_ty) = sig.decl.output { Some(ret_ty.span) } else { None }
774+
}
775+
763776
/// If all conditions are met to identify a returned `dyn Trait`, suggest using `impl Trait` if
764777
/// applicable and signal that the error has been expanded appropriately and needs to be
765778
/// emitted.

src/test/ui/issues/issue-32709.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
error[E0277]: `?` couldn't convert the error to `()`
22
--> $DIR/issue-32709.rs:4:11
33
|
4+
LL | fn a() -> Result<i32, ()> {
5+
| --------------- expected `()` because of this
46
LL | Err(5)?;
57
| ^ the trait `std::convert::From<{integer}>` is not implemented for `()`
68
|

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

+6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
error[E0277]: `?` couldn't convert the error to `()`
22
--> $DIR/option-to-result.rs:5:6
33
|
4+
LL | fn test_result() -> Result<(),()> {
5+
| ------------- expected `()` because of this
6+
LL | let a:Option<()> = Some(());
47
LL | a?;
58
| ^ the trait `std::convert::From<std::option::NoneError>` is not implemented for `()`
69
|
@@ -14,6 +17,9 @@ LL | a.ok_or_else(|| /* error value */)?;
1417
error[E0277]: `?` couldn't convert the error to `std::option::NoneError`
1518
--> $DIR/option-to-result.rs:11:6
1619
|
20+
LL | fn test_option() -> Option<i32>{
21+
| ----------- expected `std::option::NoneError` because of this
22+
LL | let a:Result<i32, i32> = Ok(5);
1723
LL | a?;
1824
| ^ the trait `std::convert::From<i32>` is not implemented for `std::option::NoneError`
1925
|

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

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
error[E0277]: `?` couldn't convert the error to `()`
22
--> $DIR/try-on-option.rs:7:6
33
|
4+
LL | fn foo() -> Result<u32, ()> {
5+
| --------------- expected `()` because of this
6+
LL | let x: Option<u32> = None;
47
LL | x?;
58
| ^ the trait `std::convert::From<std::option::NoneError>` is not implemented for `()`
69
|

0 commit comments

Comments
 (0)