]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc/infer/error_reporting/mod.rs
Reword label as per review comment
[rust.git] / src / librustc / infer / error_reporting / mod.rs
index d213a5c56187141f6f169ca93affa41617bacfbf..eec92675af6811957923fbb9fc2d1d7f8bf28d91 100644 (file)
@@ -1,13 +1,3 @@
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 //! Error Reporting Code for the inference engine
 //!
 //! Because of the way inference, and in particular region inference,
@@ -142,12 +132,14 @@ pub fn note_and_explain_region(
 
             ty::ReEmpty => ("the empty lifetime".to_owned(), None),
 
+            ty::RePlaceholder(_) => (format!("any other region"), None),
+
             // FIXME(#13998) RePlaceholder should probably print like
             // ReFree rather than dumping Debug output on the user.
             //
             // We shouldn't really be having unification failures with ReVar
             // and ReLateBound though.
-            ty::RePlaceholder(..) | ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
+            ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
                 (format!("lifetime {:?}", region), None)
             }
 
@@ -334,8 +326,13 @@ pub fn report_region_errors(
                     // the error. If all of these fails, we fall back to a rather
                     // general bit of code that displays the error information
                     RegionResolutionError::ConcreteFailure(origin, sub, sup) => {
-                        self.report_concrete_failure(region_scope_tree, origin, sub, sup)
-                            .emit();
+                        if sub.is_placeholder() || sup.is_placeholder() {
+                            self.report_placeholder_failure(region_scope_tree, origin, sub, sup)
+                                .emit();
+                        } else {
+                            self.report_concrete_failure(region_scope_tree, origin, sub, sup)
+                                .emit();
+                        }
                     }
 
                     RegionResolutionError::GenericBoundFailure(origin, param_ty, sub) => {
@@ -349,20 +346,39 @@ pub fn report_region_errors(
                     }
 
                     RegionResolutionError::SubSupConflict(
+                        _,
                         var_origin,
                         sub_origin,
                         sub_r,
                         sup_origin,
                         sup_r,
                     ) => {
-                        self.report_sub_sup_conflict(
-                            region_scope_tree,
-                            var_origin,
-                            sub_origin,
-                            sub_r,
-                            sup_origin,
-                            sup_r,
-                        );
+                        if sub_r.is_placeholder() {
+                            self.report_placeholder_failure(
+                                region_scope_tree,
+                                sub_origin,
+                                sub_r,
+                                sup_r,
+                            )
+                                .emit();
+                        } else if sup_r.is_placeholder() {
+                            self.report_placeholder_failure(
+                                region_scope_tree,
+                                sup_origin,
+                                sub_r,
+                                sup_r,
+                            )
+                                .emit();
+                        } else {
+                            self.report_sub_sup_conflict(
+                                region_scope_tree,
+                                var_origin,
+                                sub_origin,
+                                sub_r,
+                                sup_origin,
+                                sup_r,
+                            );
+                        }
                     }
                 }
             }
@@ -417,7 +433,7 @@ fn process_errors(
         errors.sort_by_key(|u| match *u {
             RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(),
             RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
-            RegionResolutionError::SubSupConflict(ref rvo, _, _, _, _) => rvo.span(),
+            RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(),
         });
         errors
     }
@@ -471,6 +487,9 @@ fn check_and_note_conflicting_crates(
 
     fn note_error_origin(&self, err: &mut DiagnosticBuilder<'tcx>, cause: &ObligationCause<'tcx>) {
         match cause.code {
+            ObligationCauseCode::MatchExpressionArmPattern { span, ty } => {
+                err.span_label(span, format!("this match expression has type `{}`", ty));
+            }
             ObligationCauseCode::MatchExpressionArm { arm_span, source } => match source {
                 hir::MatchSource::IfLetDesugar { .. } => {
                     let msg = "`if let` arm with an incompatible type";
@@ -966,6 +985,7 @@ pub fn note_type_err(
                                 diag.span_label(span, message);
                             }
                         }
+                        self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
                     }
 
                     diag.note_expected_found(&"type", expected, found);
@@ -982,6 +1002,72 @@ pub fn note_type_err(
         self.note_error_origin(diag, &cause);
     }
 
+    /// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate,
+    /// suggest it.
+    fn suggest_as_ref_where_appropriate(
+        &self,
+        span: Span,
+        exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
+        diag: &mut DiagnosticBuilder<'tcx>,
+    ) {
+        match (&exp_found.expected.sty, &exp_found.found.sty) {
+            (TyKind::Adt(exp_def, exp_substs), TyKind::Ref(_, found_ty, _)) => {
+                if let TyKind::Adt(found_def, found_substs) = found_ty.sty {
+                    let path_str = format!("{:?}", exp_def);
+                    if exp_def == &found_def {
+                        let opt_msg = "you can convert from `&Option<T>` to `Option<&T>` using \
+                                       `.as_ref()`";
+                        let result_msg = "you can convert from `&Result<T, E>` to \
+                                          `Result<&T, &E>` using `.as_ref()`";
+                        let have_as_ref = &[
+                            ("std::option::Option", opt_msg),
+                            ("core::option::Option", opt_msg),
+                            ("std::result::Result", result_msg),
+                            ("core::result::Result", result_msg),
+                        ];
+                        if let Some(msg) = have_as_ref.iter()
+                            .filter_map(|(path, msg)| if &path_str == path {
+                                Some(msg)
+                            } else {
+                                None
+                            }).next()
+                        {
+                            let mut show_suggestion = true;
+                            for (exp_ty, found_ty) in exp_substs.types().zip(found_substs.types()) {
+                                match exp_ty.sty {
+                                    TyKind::Ref(_, exp_ty, _) => {
+                                        match (&exp_ty.sty, &found_ty.sty) {
+                                            (_, TyKind::Param(_)) |
+                                            (_, TyKind::Infer(_)) |
+                                            (TyKind::Param(_), _) |
+                                            (TyKind::Infer(_), _) => {}
+                                            _ if ty::TyS::same_type(exp_ty, found_ty) => {}
+                                            _ => show_suggestion = false,
+                                        };
+                                    }
+                                    TyKind::Param(_) | TyKind::Infer(_) => {}
+                                    _ => show_suggestion = false,
+                                }
+                            }
+                            if let (Ok(snippet), true) = (
+                                self.tcx.sess.source_map().span_to_snippet(span),
+                                show_suggestion,
+                            ) {
+                                diag.span_suggestion_with_applicability(
+                                    span,
+                                    msg,
+                                    format!("{}.as_ref()", snippet),
+                                    Applicability::MachineApplicable,
+                                );
+                            }
+                        }
+                    }
+                }
+            }
+            _ => {}
+        }
+    }
+
     pub fn report_and_explain_type_error(
         &self,
         trace: TypeTrace<'tcx>,
@@ -1249,6 +1335,16 @@ fn report_sub_sup_conflict(
 
         match (&sup_origin, &sub_origin) {
             (&infer::Subtype(ref sup_trace), &infer::Subtype(ref sub_trace)) => {
+                debug!("report_sub_sup_conflict: var_origin={:?}", var_origin);
+                debug!("report_sub_sup_conflict: sub_region={:?}", sub_region);
+                debug!("report_sub_sup_conflict: sub_origin={:?}", sub_origin);
+                debug!("report_sub_sup_conflict: sup_region={:?}", sup_region);
+                debug!("report_sub_sup_conflict: sup_origin={:?}", sup_origin);
+                debug!("report_sub_sup_conflict: sup_trace={:?}", sup_trace);
+                debug!("report_sub_sup_conflict: sub_trace={:?}", sub_trace);
+                debug!("report_sub_sup_conflict: sup_trace.values={:?}", sup_trace.values);
+                debug!("report_sub_sup_conflict: sub_trace.values={:?}", sub_trace.values);
+
                 if let (Some((sup_expected, sup_found)), Some((sub_expected, sub_found))) = (
                     self.values_str(&sup_trace.values),
                     self.values_str(&sub_trace.values),