]> 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.62.1+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;
5099ac24 5use crate::infer::{SubregionOrigin, Subtype};
e74abb32 6use crate::traits::ObligationCauseCode::CompareImplMethodObligation;
04454e1e 7use rustc_errors::{ErrorGuaranteed, MultiSpan};
f9f354fc
XL
8use rustc_hir as hir;
9use rustc_hir::def::Res;
5e7ed085 10use rustc_hir::def_id::{DefId, LocalDefId};
f9f354fc 11use rustc_hir::intravisit::Visitor;
5099ac24 12use rustc_middle::hir::nested_filter;
3c0e092e
XL
13use rustc_middle::ty::print::RegionHighlightMode;
14use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
04454e1e 15use rustc_span::{Span, Symbol};
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(
5e7ed085
FG
25 _, var_origin, sub_origin, _sub, sup_origin, _sup, _,
26 ) = error.clone()
27 && let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = (&sup_origin, &sub_origin)
28 && let (
29 sub_expected_found @ Some((sub_expected, sub_found)),
30 sup_expected_found @ Some(_),
31 CompareImplMethodObligation { trait_item_def_id, .. },
32 ) = (sub_trace.values.ty(), sup_trace.values.ty(), sub_trace.cause.code())
33 && sup_expected_found == sub_expected_found
c295e0f8 34 {
5e7ed085
FG
35 let guar = self.emit_err(
36 var_origin.span(),
37 sub_expected,
38 sub_found,
39 *trait_item_def_id,
40 );
41 return Some(guar);
e74abb32 42 }
c295e0f8 43 if let RegionResolutionError::ConcreteFailure(origin, _, _)
5e7ed085
FG
44 | RegionResolutionError::GenericBoundFailure(origin, _, _) = error.clone()
45 && let SubregionOrigin::CompareImplTypeObligation {
c295e0f8 46 span,
c295e0f8
XL
47 impl_item_def_id,
48 trait_item_def_id,
49 } = origin
5e7ed085
FG
50 {
51 let guar = self.emit_associated_type_err(
52 span,
53 self.infcx.tcx.item_name(impl_item_def_id.to_def_id()),
54 impl_item_def_id,
55 trait_item_def_id,
56 );
57 return Some(guar);
c295e0f8 58 }
e74abb32
XL
59 None
60 }
61
5e7ed085
FG
62 fn emit_err(
63 &self,
64 sp: Span,
65 expected: Ty<'tcx>,
66 found: Ty<'tcx>,
67 trait_def_id: DefId,
68 ) -> ErrorGuaranteed {
f9f354fc 69 let trait_sp = self.tcx().def_span(trait_def_id);
dfeec247
XL
70 let mut err = self
71 .tcx()
72 .sess
73 .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature");
3c0e092e
XL
74
75 // Mark all unnamed regions in the type with a number.
76 // This diagnostic is called in response to lifetime errors, so be informative.
77 struct HighlightBuilder<'tcx> {
5099ac24 78 highlight: RegionHighlightMode<'tcx>,
3c0e092e
XL
79 counter: usize,
80 }
81
a2a8927a 82 impl<'tcx> HighlightBuilder<'tcx> {
5099ac24 83 fn build(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> RegionHighlightMode<'tcx> {
3c0e092e 84 let mut builder =
5099ac24 85 HighlightBuilder { highlight: RegionHighlightMode::new(tcx), counter: 1 };
3c0e092e
XL
86 builder.visit_ty(ty);
87 builder.highlight
88 }
89 }
90
91 impl<'tcx> ty::fold::TypeVisitor<'tcx> for HighlightBuilder<'tcx> {
3c0e092e
XL
92 fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
93 if !r.has_name() && self.counter <= 3 {
94 self.highlight.highlighting_region(r, self.counter);
95 self.counter += 1;
96 }
97 r.super_visit_with(self)
98 }
99 }
100
101 let expected_highlight = HighlightBuilder::build(self.tcx(), expected);
102 let expected = self
103 .infcx
104 .extract_inference_diagnostics_data(expected.into(), Some(expected_highlight))
105 .name;
106 let found_highlight = HighlightBuilder::build(self.tcx(), found);
107 let found =
108 self.infcx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
109
1b1a35ee
XL
110 err.span_label(sp, &format!("found `{}`", found));
111 err.span_label(trait_sp, &format!("expected `{}`", expected));
f9f354fc
XL
112
113 // Get the span of all the used type parameters in the method.
114 let assoc_item = self.tcx().associated_item(trait_def_id);
115 let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
116 match assoc_item.kind {
117 ty::AssocKind::Fn => {
118 let hir = self.tcx().hir();
3dfed10e
XL
119 if let Some(hir_id) =
120 assoc_item.def_id.as_local().map(|id| hir.local_def_id_to_hir_id(id))
f9f354fc
XL
121 {
122 if let Some(decl) = hir.fn_decl_by_hir_id(hir_id) {
123 visitor.visit_fn_decl(decl);
124 }
125 }
126 }
127 _ => {}
128 }
f035d41b 129 let mut type_param_span: MultiSpan = visitor.types.to_vec().into();
f9f354fc
XL
130 for &span in &visitor.types {
131 type_param_span.push_span_label(
132 span,
133 "consider borrowing this type parameter in the trait".to_string(),
134 );
135 }
136
3c0e092e
XL
137 err.note(&format!("expected `{}`\n found `{}`", expected, found));
138
f9f354fc
XL
139 err.span_help(
140 type_param_span,
141 "the lifetime requirements from the `impl` do not correspond to the requirements in \
142 the `trait`",
143 );
144 if visitor.types.is_empty() {
145 err.help(
146 "verify the lifetime relationships in the `trait` and `impl` between the `self` \
147 argument, the other inputs and its output",
148 );
149 }
5e7ed085 150 err.emit()
e74abb32 151 }
c295e0f8
XL
152
153 fn emit_associated_type_err(
154 &self,
155 span: Span,
156 item_name: Symbol,
5e7ed085 157 impl_item_def_id: LocalDefId,
c295e0f8 158 trait_item_def_id: DefId,
5e7ed085 159 ) -> ErrorGuaranteed {
c295e0f8
XL
160 let impl_sp = self.tcx().def_span(impl_item_def_id);
161 let trait_sp = self.tcx().def_span(trait_item_def_id);
162 let mut err = self
163 .tcx()
164 .sess
165 .struct_span_err(span, &format!("`impl` associated type signature for `{}` doesn't match `trait` associated type signature", item_name));
166 err.span_label(impl_sp, "found");
167 err.span_label(trait_sp, "expected");
168
5e7ed085 169 err.emit()
c295e0f8 170 }
e74abb32 171}
f9f354fc
XL
172
173struct TypeParamSpanVisitor<'tcx> {
174 tcx: TyCtxt<'tcx>,
175 types: Vec<Span>,
176}
177
a2a8927a 178impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
5099ac24 179 type NestedFilter = nested_filter::OnlyBodies;
f9f354fc 180
5099ac24
FG
181 fn nested_visit_map(&mut self) -> Self::Map {
182 self.tcx.hir()
f9f354fc
XL
183 }
184
185 fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
186 match arg.kind {
187 hir::TyKind::Rptr(_, ref mut_ty) => {
188 // We don't want to suggest looking into borrowing `&T` or `&Self`.
189 hir::intravisit::walk_ty(self, mut_ty.ty);
190 return;
191 }
192 hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
193 [segment]
194 if segment
195 .res
5869c6ff
XL
196 .map(|res| {
197 matches!(
198 res,
5099ac24
FG
199 Res::SelfTy { trait_: _, alias_to: _ }
200 | Res::Def(hir::def::DefKind::TyParam, _)
5869c6ff 201 )
f9f354fc
XL
202 })
203 .unwrap_or(false) =>
204 {
205 self.types.push(path.span);
206 }
207 _ => {}
208 },
209 _ => {}
210 }
211 hir::intravisit::walk_ty(self, arg);
212 }
213}