1 //! Error Reporting for `impl` items that do not match the obligations from their `trait`.
3 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
4 use crate::infer::lexical_region_resolve::RegionResolutionError;
5 use crate::infer::{SubregionOrigin, Subtype};
6 use crate::traits::ObligationCauseCode::CompareImplMethodObligation;
7 use rustc_errors::ErrorReported;
9 use rustc_hir::def::Res;
10 use rustc_hir::def_id::DefId;
11 use rustc_hir::intravisit::Visitor;
12 use rustc_middle::hir::nested_filter;
13 use rustc_middle::ty::print::RegionHighlightMode;
14 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
16 use rustc_span::{MultiSpan, Span, Symbol};
18 use std::ops::ControlFlow;
20 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
21 /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
22 pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option<ErrorReported> {
23 let error = self.error.as_ref()?;
24 debug!("try_report_impl_not_conforming_to_trait {:?}", error);
25 if let RegionResolutionError::SubSupConflict(
35 if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = (&sup_origin, &sub_origin) {
37 sub_expected_found @ Some((sub_expected, sub_found)),
38 sup_expected_found @ Some(_),
39 CompareImplMethodObligation { trait_item_def_id, .. },
40 ) = (&sub_trace.values.ty(), &sup_trace.values.ty(), sub_trace.cause.code())
42 if sup_expected_found == sub_expected_found {
49 return Some(ErrorReported);
54 if let RegionResolutionError::ConcreteFailure(origin, _, _)
55 | RegionResolutionError::GenericBoundFailure(origin, _, _) = error.clone()
57 if let SubregionOrigin::CompareImplTypeObligation {
63 self.emit_associated_type_err(
65 self.infcx.tcx.item_name(impl_item_def_id),
69 return Some(ErrorReported);
75 fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, trait_def_id: DefId) {
76 let trait_sp = self.tcx().def_span(trait_def_id);
80 .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature");
82 // Mark all unnamed regions in the type with a number.
83 // This diagnostic is called in response to lifetime errors, so be informative.
84 struct HighlightBuilder {
85 highlight: RegionHighlightMode,
89 impl HighlightBuilder {
90 fn build(ty: Ty<'_>) -> RegionHighlightMode {
92 HighlightBuilder { highlight: RegionHighlightMode::default(), counter: 1 };
98 impl<'tcx> ty::fold::TypeVisitor<'tcx> for HighlightBuilder {
99 fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
100 if !r.has_name() && self.counter <= 3 {
101 self.highlight.highlighting_region(r, self.counter);
104 r.super_visit_with(self)
108 let expected_highlight = HighlightBuilder::build(expected);
111 .extract_inference_diagnostics_data(expected.into(), Some(expected_highlight))
113 let found_highlight = HighlightBuilder::build(found);
115 self.infcx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
117 err.span_label(sp, &format!("found `{}`", found));
118 err.span_label(trait_sp, &format!("expected `{}`", expected));
120 // Get the span of all the used type parameters in the method.
121 let assoc_item = self.tcx().associated_item(trait_def_id);
122 let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
123 match assoc_item.kind {
124 ty::AssocKind::Fn => {
125 let hir = self.tcx().hir();
126 if let Some(hir_id) =
127 assoc_item.def_id.as_local().map(|id| hir.local_def_id_to_hir_id(id))
129 if let Some(decl) = hir.fn_decl_by_hir_id(hir_id) {
130 visitor.visit_fn_decl(decl);
136 let mut type_param_span: MultiSpan = visitor.types.to_vec().into();
137 for &span in &visitor.types {
138 type_param_span.push_span_label(
140 "consider borrowing this type parameter in the trait".to_string(),
144 err.note(&format!("expected `{}`\n found `{}`", expected, found));
148 "the lifetime requirements from the `impl` do not correspond to the requirements in \
151 if visitor.types.is_empty() {
153 "verify the lifetime relationships in the `trait` and `impl` between the `self` \
154 argument, the other inputs and its output",
160 fn emit_associated_type_err(
164 impl_item_def_id: DefId,
165 trait_item_def_id: DefId,
167 let impl_sp = self.tcx().def_span(impl_item_def_id);
168 let trait_sp = self.tcx().def_span(trait_item_def_id);
172 .struct_span_err(span, &format!("`impl` associated type signature for `{}` doesn't match `trait` associated type signature", item_name));
173 err.span_label(impl_sp, "found");
174 err.span_label(trait_sp, "expected");
180 struct TypeParamSpanVisitor<'tcx> {
185 impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
186 type NestedFilter = nested_filter::OnlyBodies;
188 fn nested_visit_map(&mut self) -> Self::Map {
192 fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
194 hir::TyKind::Rptr(_, ref mut_ty) => {
195 // We don't want to suggest looking into borrowing `&T` or `&Self`.
196 hir::intravisit::walk_ty(self, mut_ty.ty);
199 hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
206 Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _)
211 self.types.push(path.span);
217 hir::intravisit::walk_ty(self, arg);