about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorDylan DPC <dylan.dpc@gmail.com>2020-04-27 03:26:13 +0200
committerGitHub <noreply@github.com>2020-04-27 03:26:13 +0200
commitc95bcbc9d5db498b572909bdcc56e684ceece68a (patch)
tree75931a16e227fced8b9fde5491e8d2a14b71096e /src
parent89aff5f33e1b28093e881e812b670672f724d8aa (diff)
parentbe90f90810438eed6f0090acfb4d29a787a43c1e (diff)
downloadrust-c95bcbc9d5db498b572909bdcc56e684ceece68a.tar.gz
rust-c95bcbc9d5db498b572909bdcc56e684ceece68a.zip
Rollup merge of #71409 - estebank:point-at-ret-question-mark-op, r=petrochenkov
Point at the return type on `.into()` failure caused by `?`

Fix #35946.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_trait_selection/traits/error_reporting/mod.rs38
-rw-r--r--src/librustc_trait_selection/traits/error_reporting/suggestions.rs13
-rw-r--r--src/test/ui/issues/issue-32709.stderr2
-rw-r--r--src/test/ui/option-to-result.stderr6
-rw-r--r--src/test/ui/try-on-option.stderr3
5 files changed, 48 insertions, 14 deletions
diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs
index fa9f1c9a7d9..35eb5d73ada 100644
--- a/src/librustc_trait_selection/traits/error_reporting/mod.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs
@@ -317,20 +317,30 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                                 .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,
-                            );
+                        if is_try && is_from {
+                            if 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 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,
+                                );
+                            }
+                            if let Some(ret_span) = self.return_type_span(obligation) {
+                                err.span_label(
+                                    ret_span,
+                                    &format!("expected `{}` because of this", trait_ref.self_ty()),
+                                );
+                            }
                         }
 
                         let explanation =
diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
index 19260f4d573..a927013e25f 100644
--- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
@@ -84,6 +84,8 @@ pub trait InferCtxtExt<'tcx> {
         trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
     );
 
+    fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span>;
+
     fn suggest_impl_trait(
         &self,
         err: &mut DiagnosticBuilder<'tcx>,
@@ -761,6 +763,17 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         }
     }
 
+    fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span> {
+        let hir = self.tcx.hir();
+        let parent_node = hir.get_parent_node(obligation.cause.body_id);
+        let sig = match hir.find(parent_node) {
+            Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. })) => sig,
+            _ => return None,
+        };
+
+        if let hir::FnRetTy::Return(ret_ty) = sig.decl.output { Some(ret_ty.span) } else { None }
+    }
+
     /// If all conditions are met to identify a returned `dyn Trait`, suggest using `impl Trait` if
     /// applicable and signal that the error has been expanded appropriately and needs to be
     /// emitted.
diff --git a/src/test/ui/issues/issue-32709.stderr b/src/test/ui/issues/issue-32709.stderr
index 04b8c3aa353..af272633f21 100644
--- a/src/test/ui/issues/issue-32709.stderr
+++ b/src/test/ui/issues/issue-32709.stderr
@@ -1,6 +1,8 @@
 error[E0277]: `?` couldn't convert the error to `()`
   --> $DIR/issue-32709.rs:4:11
    |
+LL | fn a() -> Result<i32, ()> {
+   |           --------------- expected `()` because of this
 LL |     Err(5)?;
    |           ^ the trait `std::convert::From<{integer}>` is not implemented for `()`
    |
diff --git a/src/test/ui/option-to-result.stderr b/src/test/ui/option-to-result.stderr
index f673ef7fc1e..5fa06778389 100644
--- a/src/test/ui/option-to-result.stderr
+++ b/src/test/ui/option-to-result.stderr
@@ -1,6 +1,9 @@
 error[E0277]: `?` couldn't convert the error to `()`
   --> $DIR/option-to-result.rs:5:6
    |
+LL | fn test_result() -> Result<(),()> {
+   |                     ------------- expected `()` because of this
+LL |     let a:Option<()> = Some(());
 LL |     a?;
    |      ^ the trait `std::convert::From<std::option::NoneError>` is not implemented for `()`
    |
@@ -14,6 +17,9 @@ 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 | fn test_option() -> Option<i32>{
+   |                     ----------- expected `std::option::NoneError` because of this
+LL |     let a:Result<i32, i32> = Ok(5);
 LL |     a?;
    |      ^ the trait `std::convert::From<i32>` is not implemented for `std::option::NoneError`
    |
diff --git a/src/test/ui/try-on-option.stderr b/src/test/ui/try-on-option.stderr
index 7a4bb75967b..33ca58bf7fe 100644
--- a/src/test/ui/try-on-option.stderr
+++ b/src/test/ui/try-on-option.stderr
@@ -1,6 +1,9 @@
 error[E0277]: `?` couldn't convert the error to `()`
   --> $DIR/try-on-option.rs:7:6
    |
+LL | fn foo() -> Result<u32, ()> {
+   |             --------------- expected `()` because of this
+LL |     let x: Option<u32> = None;
 LL |     x?;
    |      ^ the trait `std::convert::From<std::option::NoneError>` is not implemented for `()`
    |