-// 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,
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)
}
// 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) => {
}
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,
+ );
+ }
}
}
}
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
}
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";
diag.span_label(span, message);
}
}
+ self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
}
diag.note_expected_found(&"type", expected, found);
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>,
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),