]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
New upstream version 1.66.0+dfsg1
[rustc.git] / compiler / rustc_infer / src / infer / error_reporting / nice_region_error / trait_impl_difference.rs
CommitLineData
e74abb32
XL
1//! Error Reporting for `impl` items that do not match the obligations from their `trait`.
2
e74abb32
XL
3use crate::infer::error_reporting::nice_region_error::NiceRegionError;
4use crate::infer::lexical_region_resolve::RegionResolutionError;
064997fb
FG
5use crate::infer::Subtype;
6use crate::traits::ObligationCauseCode::CompareImplItemObligation;
04454e1e 7use rustc_errors::{ErrorGuaranteed, MultiSpan};
f9f354fc
XL
8use rustc_hir as hir;
9use rustc_hir::def::Res;
064997fb 10use rustc_hir::def_id::DefId;
f9f354fc 11use rustc_hir::intravisit::Visitor;
5099ac24 12use rustc_middle::hir::nested_filter;
3c0e092e 13use rustc_middle::ty::print::RegionHighlightMode;
064997fb
FG
14use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
15use rustc_span::Span;
e74abb32 16
3c0e092e
XL
17use std::ops::ControlFlow;
18
e74abb32
XL
19impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
20 /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
5e7ed085 21 pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option<ErrorGuaranteed> {
c295e0f8
XL
22 let error = self.error.as_ref()?;
23 debug!("try_report_impl_not_conforming_to_trait {:?}", error);
24 if let RegionResolutionError::SubSupConflict(
064997fb
FG
25 _,
26 var_origin,
27 sub_origin,
28 _sub,
29 sup_origin,
30 _sup,
31 _,
5e7ed085 32 ) = error.clone()
064997fb
FG
33 && let (Subtype(sup_trace), Subtype(sub_trace)) = (&sup_origin, &sub_origin)
34 && let sub_expected_found @ Some((sub_expected, sub_found)) = sub_trace.values.ty()
35 && let sup_expected_found @ Some(_) = sup_trace.values.ty()
36 && let CompareImplItemObligation { trait_item_def_id, .. } = sub_trace.cause.code()
5e7ed085 37 && sup_expected_found == sub_expected_found
c295e0f8 38 {
064997fb
FG
39 let guar =
40 self.emit_err(var_origin.span(), sub_expected, sub_found, *trait_item_def_id);
5e7ed085 41 return Some(guar);
c295e0f8 42 }
e74abb32
XL
43 None
44 }
45
5e7ed085
FG
46 fn emit_err(
47 &self,
48 sp: Span,
49 expected: Ty<'tcx>,
50 found: Ty<'tcx>,
51 trait_def_id: DefId,
52 ) -> ErrorGuaranteed {
f9f354fc 53 let trait_sp = self.tcx().def_span(trait_def_id);
dfeec247
XL
54 let mut err = self
55 .tcx()
56 .sess
57 .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature");
3c0e092e
XL
58
59 // Mark all unnamed regions in the type with a number.
60 // This diagnostic is called in response to lifetime errors, so be informative.
61 struct HighlightBuilder<'tcx> {
5099ac24 62 highlight: RegionHighlightMode<'tcx>,
3c0e092e
XL
63 counter: usize,
64 }
65
a2a8927a 66 impl<'tcx> HighlightBuilder<'tcx> {
5099ac24 67 fn build(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> RegionHighlightMode<'tcx> {
3c0e092e 68 let mut builder =
5099ac24 69 HighlightBuilder { highlight: RegionHighlightMode::new(tcx), counter: 1 };
3c0e092e
XL
70 builder.visit_ty(ty);
71 builder.highlight
72 }
73 }
74
064997fb 75 impl<'tcx> ty::visit::TypeVisitor<'tcx> for HighlightBuilder<'tcx> {
3c0e092e
XL
76 fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
77 if !r.has_name() && self.counter <= 3 {
78 self.highlight.highlighting_region(r, self.counter);
79 self.counter += 1;
80 }
81 r.super_visit_with(self)
82 }
83 }
84
85 let expected_highlight = HighlightBuilder::build(self.tcx(), expected);
86 let expected = self
2b03887a 87 .cx
3c0e092e
XL
88 .extract_inference_diagnostics_data(expected.into(), Some(expected_highlight))
89 .name;
90 let found_highlight = HighlightBuilder::build(self.tcx(), found);
91 let found =
2b03887a 92 self.cx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
3c0e092e 93
1b1a35ee
XL
94 err.span_label(sp, &format!("found `{}`", found));
95 err.span_label(trait_sp, &format!("expected `{}`", expected));
f9f354fc
XL
96
97 // Get the span of all the used type parameters in the method.
98 let assoc_item = self.tcx().associated_item(trait_def_id);
99 let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
100 match assoc_item.kind {
101 ty::AssocKind::Fn => {
102 let hir = self.tcx().hir();
3dfed10e
XL
103 if let Some(hir_id) =
104 assoc_item.def_id.as_local().map(|id| hir.local_def_id_to_hir_id(id))
f9f354fc
XL
105 {
106 if let Some(decl) = hir.fn_decl_by_hir_id(hir_id) {
107 visitor.visit_fn_decl(decl);
108 }
109 }
110 }
111 _ => {}
112 }
f035d41b 113 let mut type_param_span: MultiSpan = visitor.types.to_vec().into();
f9f354fc 114 for &span in &visitor.types {
064997fb
FG
115 type_param_span
116 .push_span_label(span, "consider borrowing this type parameter in the trait");
f9f354fc
XL
117 }
118
3c0e092e
XL
119 err.note(&format!("expected `{}`\n found `{}`", expected, found));
120
f9f354fc
XL
121 err.span_help(
122 type_param_span,
123 "the lifetime requirements from the `impl` do not correspond to the requirements in \
124 the `trait`",
125 );
126 if visitor.types.is_empty() {
127 err.help(
128 "verify the lifetime relationships in the `trait` and `impl` between the `self` \
129 argument, the other inputs and its output",
130 );
131 }
5e7ed085 132 err.emit()
e74abb32
XL
133 }
134}
f9f354fc
XL
135
136struct TypeParamSpanVisitor<'tcx> {
137 tcx: TyCtxt<'tcx>,
138 types: Vec<Span>,
139}
140
a2a8927a 141impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
5099ac24 142 type NestedFilter = nested_filter::OnlyBodies;
f9f354fc 143
5099ac24
FG
144 fn nested_visit_map(&mut self) -> Self::Map {
145 self.tcx.hir()
f9f354fc
XL
146 }
147
148 fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
149 match arg.kind {
150 hir::TyKind::Rptr(_, ref mut_ty) => {
151 // We don't want to suggest looking into borrowing `&T` or `&Self`.
152 hir::intravisit::walk_ty(self, mut_ty.ty);
153 return;
154 }
155 hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
156 [segment]
f2b60f7d
FG
157 if matches!(
158 segment.res,
2b03887a
FG
159 Res::SelfTyParam { .. }
160 | Res::SelfTyAlias { .. }
f2b60f7d
FG
161 | Res::Def(hir::def::DefKind::TyParam, _)
162 ) =>
f9f354fc
XL
163 {
164 self.types.push(path.span);
165 }
166 _ => {}
167 },
168 _ => {}
169 }
170 hir::intravisit::walk_ty(self, arg);
171 }
172}