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