]> git.lizzy.rs Git - rust.git/blob - src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs
Rollup merge of #75485 - RalfJung:pin, r=nagisa
[rust.git] / src / librustc_infer / 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::{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::error::ExpectedFound;
13 use rustc_middle::ty::{self, Ty, TyCtxt};
14 use rustc_span::{MultiSpan, Span};
15
16 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
17     /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
18     pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option<ErrorReported> {
19         if let Some(ref error) = self.error {
20             debug!("try_report_impl_not_conforming_to_trait {:?}", error);
21             if let RegionResolutionError::SubSupConflict(
22                 _,
23                 var_origin,
24                 sub_origin,
25                 _sub,
26                 sup_origin,
27                 _sup,
28             ) = error.clone()
29             {
30                 if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) =
31                     (&sup_origin, &sub_origin)
32                 {
33                     if let (
34                         ValuePairs::Types(sub_expected_found),
35                         ValuePairs::Types(sup_expected_found),
36                         CompareImplMethodObligation { trait_item_def_id, .. },
37                     ) = (&sub_trace.values, &sup_trace.values, &sub_trace.cause.code)
38                     {
39                         if sup_expected_found == sub_expected_found {
40                             self.emit_err(
41                                 var_origin.span(),
42                                 sub_expected_found.expected,
43                                 sub_expected_found.found,
44                                 *trait_item_def_id,
45                             );
46                             return Some(ErrorReported);
47                         }
48                     }
49                 }
50             }
51         }
52         None
53     }
54
55     fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, trait_def_id: DefId) {
56         let trait_sp = self.tcx().def_span(trait_def_id);
57         let mut err = self
58             .tcx()
59             .sess
60             .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature");
61         err.span_label(sp, &format!("found `{:?}`", found));
62         err.span_label(trait_sp, &format!("expected `{:?}`", expected));
63
64         // Get the span of all the used type parameters in the method.
65         let assoc_item = self.tcx().associated_item(trait_def_id);
66         let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
67         match assoc_item.kind {
68             ty::AssocKind::Fn => {
69                 let hir = self.tcx().hir();
70                 if let Some(hir_id) =
71                     assoc_item.def_id.as_local().map(|id| hir.local_def_id_to_hir_id(id))
72                 {
73                     if let Some(decl) = hir.fn_decl_by_hir_id(hir_id) {
74                         visitor.visit_fn_decl(decl);
75                     }
76                 }
77             }
78             _ => {}
79         }
80         let mut type_param_span: MultiSpan = visitor.types.to_vec().into();
81         for &span in &visitor.types {
82             type_param_span.push_span_label(
83                 span,
84                 "consider borrowing this type parameter in the trait".to_string(),
85             );
86         }
87
88         if let Some((expected, found)) =
89             self.infcx.expected_found_str_ty(&ExpectedFound { expected, found })
90         {
91             // Highlighted the differences when showing the "expected/found" note.
92             err.note_expected_found(&"", expected, &"", found);
93         } else {
94             // This fallback shouldn't be necessary, but let's keep it in just in case.
95             err.note(&format!("expected `{:?}`\n   found `{:?}`", expected, found));
96         }
97         err.span_help(
98             type_param_span,
99             "the lifetime requirements from the `impl` do not correspond to the requirements in \
100              the `trait`",
101         );
102         if visitor.types.is_empty() {
103             err.help(
104                 "verify the lifetime relationships in the `trait` and `impl` between the `self` \
105                  argument, the other inputs and its output",
106             );
107         }
108         err.emit();
109     }
110 }
111
112 struct TypeParamSpanVisitor<'tcx> {
113     tcx: TyCtxt<'tcx>,
114     types: Vec<Span>,
115 }
116
117 impl Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
118     type Map = rustc_middle::hir::map::Map<'tcx>;
119
120     fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
121         hir::intravisit::NestedVisitorMap::OnlyBodies(self.tcx.hir())
122     }
123
124     fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
125         match arg.kind {
126             hir::TyKind::Rptr(_, ref mut_ty) => {
127                 // We don't want to suggest looking into borrowing `&T` or `&Self`.
128                 hir::intravisit::walk_ty(self, mut_ty.ty);
129                 return;
130             }
131             hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
132                 [segment]
133                     if segment
134                         .res
135                         .map(|res| match res {
136                             Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _) => true,
137                             _ => false,
138                         })
139                         .unwrap_or(false) =>
140                 {
141                     self.types.push(path.span);
142                 }
143                 _ => {}
144             },
145             _ => {}
146         }
147         hir::intravisit::walk_ty(self, arg);
148     }
149 }