• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Error Reporting for `impl` items that do not match the obligations from their `trait`.
2 
3 use crate::errors::{ConsiderBorrowingParamHelp, RelationshipHelp, TraitImplDiff};
4 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
5 use crate::infer::lexical_region_resolve::RegionResolutionError;
6 use crate::infer::{Subtype, ValuePairs};
7 use crate::traits::ObligationCauseCode::CompareImplItemObligation;
8 use rustc_errors::ErrorGuaranteed;
9 use rustc_hir as hir;
10 use rustc_hir::def::Res;
11 use rustc_hir::def_id::DefId;
12 use rustc_hir::intravisit::Visitor;
13 use rustc_middle::hir::nested_filter;
14 use rustc_middle::ty::error::ExpectedFound;
15 use rustc_middle::ty::print::RegionHighlightMode;
16 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
17 use rustc_span::Span;
18 
19 use std::ops::ControlFlow;
20 
21 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
22     /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
try_report_impl_not_conforming_to_trait(&self) -> Option<ErrorGuaranteed>23     pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option<ErrorGuaranteed> {
24         let error = self.error.as_ref()?;
25         debug!("try_report_impl_not_conforming_to_trait {:?}", error);
26         if let RegionResolutionError::SubSupConflict(
27             _,
28             var_origin,
29             sub_origin,
30             _sub,
31             sup_origin,
32             _sup,
33             _,
34         ) = error.clone()
35             && let (Subtype(sup_trace), Subtype(sub_trace)) = (&sup_origin, &sub_origin)
36             && let CompareImplItemObligation { trait_item_def_id, .. } = sub_trace.cause.code()
37             && sub_trace.values == sup_trace.values
38             && let ValuePairs::Sigs(ExpectedFound { expected, found }) = sub_trace.values
39         {
40             // FIXME(compiler-errors): Don't like that this needs `Ty`s, but
41             // all of the region highlighting machinery only deals with those.
42             let guar = self.emit_err(
43                 var_origin.span(),
44                 Ty::new_fn_ptr(self.cx.tcx,ty::Binder::dummy(expected)),
45                 Ty::new_fn_ptr(self.cx.tcx,ty::Binder::dummy(found)),
46                 *trait_item_def_id,
47             );
48             return Some(guar);
49         }
50         None
51     }
52 
emit_err( &self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, trait_def_id: DefId, ) -> ErrorGuaranteed53     fn emit_err(
54         &self,
55         sp: Span,
56         expected: Ty<'tcx>,
57         found: Ty<'tcx>,
58         trait_def_id: DefId,
59     ) -> ErrorGuaranteed {
60         let trait_sp = self.tcx().def_span(trait_def_id);
61 
62         // Mark all unnamed regions in the type with a number.
63         // This diagnostic is called in response to lifetime errors, so be informative.
64         struct HighlightBuilder<'tcx> {
65             highlight: RegionHighlightMode<'tcx>,
66             counter: usize,
67         }
68 
69         impl<'tcx> HighlightBuilder<'tcx> {
70             fn build(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> RegionHighlightMode<'tcx> {
71                 let mut builder =
72                     HighlightBuilder { highlight: RegionHighlightMode::new(tcx), counter: 1 };
73                 builder.visit_ty(ty);
74                 builder.highlight
75             }
76         }
77 
78         impl<'tcx> ty::visit::TypeVisitor<TyCtxt<'tcx>> for HighlightBuilder<'tcx> {
79             fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
80                 if !r.has_name() && self.counter <= 3 {
81                     self.highlight.highlighting_region(r, self.counter);
82                     self.counter += 1;
83                 }
84                 ControlFlow::Continue(())
85             }
86         }
87 
88         let expected_highlight = HighlightBuilder::build(self.tcx(), expected);
89         let expected = self
90             .cx
91             .extract_inference_diagnostics_data(expected.into(), Some(expected_highlight))
92             .name;
93         let found_highlight = HighlightBuilder::build(self.tcx(), found);
94         let found =
95             self.cx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
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();
103                 if let Some(hir_id) =
104                     assoc_item.def_id.as_local().map(|id| hir.local_def_id_to_hir_id(id))
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         }
113 
114         let diag = TraitImplDiff {
115             sp,
116             trait_sp,
117             note: (),
118             param_help: ConsiderBorrowingParamHelp { spans: visitor.types.to_vec() },
119             rel_help: visitor.types.is_empty().then_some(RelationshipHelp),
120             expected,
121             found,
122         };
123 
124         self.tcx().sess.emit_err(diag)
125     }
126 }
127 
128 struct TypeParamSpanVisitor<'tcx> {
129     tcx: TyCtxt<'tcx>,
130     types: Vec<Span>,
131 }
132 
133 impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
134     type NestedFilter = nested_filter::OnlyBodies;
135 
nested_visit_map(&mut self) -> Self::Map136     fn nested_visit_map(&mut self) -> Self::Map {
137         self.tcx.hir()
138     }
139 
visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>)140     fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
141         match arg.kind {
142             hir::TyKind::Ref(_, ref mut_ty) => {
143                 // We don't want to suggest looking into borrowing `&T` or `&Self`.
144                 hir::intravisit::walk_ty(self, mut_ty.ty);
145                 return;
146             }
147             hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
148                 [segment]
149                     if matches!(
150                         segment.res,
151                         Res::SelfTyParam { .. }
152                             | Res::SelfTyAlias { .. }
153                             | Res::Def(hir::def::DefKind::TyParam, _)
154                     ) =>
155                 {
156                     self.types.push(path.span);
157                 }
158                 _ => {}
159             },
160             _ => {}
161         }
162         hir::intravisit::walk_ty(self, arg);
163     }
164 }
165