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