about summary refs log tree commit diff
path: root/src/librustc_trait_selection
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2020-04-21 17:20:12 -0700
committerEsteban Küber <esteban@kuber.com.ar>2020-04-26 11:50:58 -0700
commitbe90f90810438eed6f0090acfb4d29a787a43c1e (patch)
tree54c47dd313519f5ff1cc0255b10cd7e7d80ead7c /src/librustc_trait_selection
parent8ce3f840ae9b735a66531996c32330f24b877cb0 (diff)
downloadrust-be90f90810438eed6f0090acfb4d29a787a43c1e.tar.gz
rust-be90f90810438eed6f0090acfb4d29a787a43c1e.zip
Point at the return type on `.into()` failure caused by `?`
Fix #35946.
Diffstat (limited to 'src/librustc_trait_selection')
-rw-r--r--src/librustc_trait_selection/traits/error_reporting/mod.rs38
-rw-r--r--src/librustc_trait_selection/traits/error_reporting/suggestions.rs13
2 files changed, 37 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 8a9017960fb..094168d5d2e 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 2b19699d6ec..ce34d5868a8 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>,
@@ -760,6 +762,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.