]>
Commit | Line | Data |
---|---|---|
e74abb32 XL |
1 | //! Error Reporting for `impl` items that do not match the obligations from their `trait`. |
2 | ||
9c376795 | 3 | use crate::errors::{ConsiderBorrowingParamHelp, RelationshipHelp, TraitImplDiff}; |
e74abb32 XL |
4 | use crate::infer::error_reporting::nice_region_error::NiceRegionError; |
5 | use crate::infer::lexical_region_resolve::RegionResolutionError; | |
9c376795 | 6 | use crate::infer::{Subtype, ValuePairs}; |
064997fb | 7 | use crate::traits::ObligationCauseCode::CompareImplItemObligation; |
9c376795 | 8 | use rustc_errors::ErrorGuaranteed; |
f9f354fc XL |
9 | use rustc_hir as hir; |
10 | use rustc_hir::def::Res; | |
064997fb | 11 | use rustc_hir::def_id::DefId; |
f9f354fc | 12 | use rustc_hir::intravisit::Visitor; |
5099ac24 | 13 | use rustc_middle::hir::nested_filter; |
9c376795 | 14 | use rustc_middle::ty::error::ExpectedFound; |
3c0e092e | 15 | use rustc_middle::ty::print::RegionHighlightMode; |
064997fb FG |
16 | use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; |
17 | use rustc_span::Span; | |
e74abb32 | 18 | |
3c0e092e XL |
19 | use std::ops::ControlFlow; |
20 | ||
e74abb32 XL |
21 | impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { |
22 | /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`. | |
5e7ed085 | 23 | pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option<ErrorGuaranteed> { |
c295e0f8 XL |
24 | let error = self.error.as_ref()?; |
25 | debug!("try_report_impl_not_conforming_to_trait {:?}", error); | |
26 | if let RegionResolutionError::SubSupConflict( | |
9c376795 FG |
27 | _, |
28 | var_origin, | |
29 | sub_origin, | |
30 | _sub, | |
31 | sup_origin, | |
32 | _sup, | |
33 | _, | |
34 | ) = error.clone() | |
064997fb | 35 | && let (Subtype(sup_trace), Subtype(sub_trace)) = (&sup_origin, &sub_origin) |
064997fb | 36 | && let CompareImplItemObligation { trait_item_def_id, .. } = sub_trace.cause.code() |
9c376795 FG |
37 | && sub_trace.values == sup_trace.values |
38 | && let ValuePairs::Sigs(ExpectedFound { expected, found }) = sub_trace.values | |
c295e0f8 | 39 | { |
9c376795 FG |
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 | self.cx.tcx.mk_fn_ptr(ty::Binder::dummy(expected)), | |
45 | self.cx.tcx.mk_fn_ptr(ty::Binder::dummy(found)), | |
46 | *trait_item_def_id, | |
47 | ); | |
5e7ed085 | 48 | return Some(guar); |
c295e0f8 | 49 | } |
e74abb32 XL |
50 | None |
51 | } | |
52 | ||
5e7ed085 FG |
53 | fn emit_err( |
54 | &self, | |
55 | sp: Span, | |
56 | expected: Ty<'tcx>, | |
57 | found: Ty<'tcx>, | |
58 | trait_def_id: DefId, | |
59 | ) -> ErrorGuaranteed { | |
f9f354fc | 60 | let trait_sp = self.tcx().def_span(trait_def_id); |
3c0e092e XL |
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> { | |
5099ac24 | 65 | highlight: RegionHighlightMode<'tcx>, |
3c0e092e XL |
66 | counter: usize, |
67 | } | |
68 | ||
a2a8927a | 69 | impl<'tcx> HighlightBuilder<'tcx> { |
5099ac24 | 70 | fn build(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> RegionHighlightMode<'tcx> { |
3c0e092e | 71 | let mut builder = |
5099ac24 | 72 | HighlightBuilder { highlight: RegionHighlightMode::new(tcx), counter: 1 }; |
3c0e092e XL |
73 | builder.visit_ty(ty); |
74 | builder.highlight | |
75 | } | |
76 | } | |
77 | ||
064997fb | 78 | impl<'tcx> ty::visit::TypeVisitor<'tcx> for HighlightBuilder<'tcx> { |
3c0e092e XL |
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 | r.super_visit_with(self) | |
85 | } | |
86 | } | |
87 | ||
88 | let expected_highlight = HighlightBuilder::build(self.tcx(), expected); | |
89 | let expected = self | |
2b03887a | 90 | .cx |
3c0e092e XL |
91 | .extract_inference_diagnostics_data(expected.into(), Some(expected_highlight)) |
92 | .name; | |
93 | let found_highlight = HighlightBuilder::build(self.tcx(), found); | |
94 | let found = | |
2b03887a | 95 | self.cx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name; |
3c0e092e | 96 | |
f9f354fc XL |
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 | } | |
f9f354fc | 113 | |
9c376795 FG |
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) | |
e74abb32 XL |
125 | } |
126 | } | |
f9f354fc XL |
127 | |
128 | struct TypeParamSpanVisitor<'tcx> { | |
129 | tcx: TyCtxt<'tcx>, | |
130 | types: Vec<Span>, | |
131 | } | |
132 | ||
a2a8927a | 133 | impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> { |
5099ac24 | 134 | type NestedFilter = nested_filter::OnlyBodies; |
f9f354fc | 135 | |
5099ac24 FG |
136 | fn nested_visit_map(&mut self) -> Self::Map { |
137 | self.tcx.hir() | |
f9f354fc XL |
138 | } |
139 | ||
140 | fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) { | |
141 | match arg.kind { | |
9c376795 | 142 | hir::TyKind::Ref(_, ref mut_ty) => { |
f9f354fc XL |
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] | |
f2b60f7d FG |
149 | if matches!( |
150 | segment.res, | |
2b03887a FG |
151 | Res::SelfTyParam { .. } |
152 | | Res::SelfTyAlias { .. } | |
f2b60f7d FG |
153 | | Res::Def(hir::def::DefKind::TyParam, _) |
154 | ) => | |
f9f354fc XL |
155 | { |
156 | self.types.push(path.span); | |
157 | } | |
158 | _ => {} | |
159 | }, | |
160 | _ => {} | |
161 | } | |
162 | hir::intravisit::walk_ty(self, arg); | |
163 | } | |
164 | } |