rustc_trait_selection/error_reporting/infer/nice_region_error/
trait_impl_difference.rs

1//! Error Reporting for `impl` items that do not match the obligations from their `trait`.
2
3use rustc_errors::ErrorGuaranteed;
4use rustc_hir::def::{Namespace, Res};
5use rustc_hir::def_id::DefId;
6use rustc_hir::intravisit::{Visitor, walk_ty};
7use rustc_hir::{self as hir, AmbigArg};
8use rustc_middle::hir::nested_filter;
9use rustc_middle::traits::ObligationCauseCode;
10use rustc_middle::ty::error::ExpectedFound;
11use rustc_middle::ty::print::RegionHighlightMode;
12use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
13use rustc_span::Span;
14use tracing::debug;
15
16use crate::error_reporting::infer::nice_region_error::NiceRegionError;
17use crate::error_reporting::infer::nice_region_error::placeholder_error::Highlighted;
18use crate::errors::{ConsiderBorrowingParamHelp, RelationshipHelp, TraitImplDiff};
19use crate::infer::{RegionResolutionError, Subtype, ValuePairs};
20
21impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
22    /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
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 &ObligationCauseCode::CompareImplItem { trait_item_def_id, .. } =
37                sub_trace.cause.code()
38            && sub_trace.values == sup_trace.values
39            && let ValuePairs::PolySigs(ExpectedFound { expected, found }) = sub_trace.values
40        {
41            // FIXME(compiler-errors): Don't like that this needs `Ty`s, but
42            // all of the region highlighting machinery only deals with those.
43            let guar = self.emit_err(var_origin.span(), expected, found, trait_item_def_id);
44            return Some(guar);
45        }
46        None
47    }
48
49    fn emit_err(
50        &self,
51        sp: Span,
52        expected: ty::PolyFnSig<'tcx>,
53        found: ty::PolyFnSig<'tcx>,
54        trait_item_def_id: DefId,
55    ) -> ErrorGuaranteed {
56        let trait_sp = self.tcx().def_span(trait_item_def_id);
57
58        // Mark all unnamed regions in the type with a number.
59        // This diagnostic is called in response to lifetime errors, so be informative.
60        struct HighlightBuilder<'tcx> {
61            highlight: RegionHighlightMode<'tcx>,
62            counter: usize,
63        }
64
65        impl<'tcx> HighlightBuilder<'tcx> {
66            fn build(sig: ty::PolyFnSig<'tcx>) -> RegionHighlightMode<'tcx> {
67                let mut builder =
68                    HighlightBuilder { highlight: RegionHighlightMode::default(), counter: 1 };
69                sig.visit_with(&mut builder);
70                builder.highlight
71            }
72        }
73
74        impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for HighlightBuilder<'tcx> {
75            fn visit_region(&mut self, r: ty::Region<'tcx>) {
76                if !r.has_name() && self.counter <= 3 {
77                    self.highlight.highlighting_region(r, self.counter);
78                    self.counter += 1;
79                }
80            }
81        }
82
83        let expected_highlight = HighlightBuilder::build(expected);
84        let tcx = self.cx.tcx;
85        let expected = Highlighted {
86            highlight: expected_highlight,
87            ns: Namespace::TypeNS,
88            tcx,
89            value: expected,
90        }
91        .to_string();
92        let found_highlight = HighlightBuilder::build(found);
93        let found =
94            Highlighted { highlight: found_highlight, ns: Namespace::TypeNS, tcx, value: found }
95                .to_string();
96
97        // Get the span of all the used type parameters in the method.
98        let assoc_item = self.tcx().associated_item(trait_item_def_id);
99        let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
100        match assoc_item.kind {
101            ty::AssocKind::Fn { .. } => {
102                if let Some(hir_id) =
103                    assoc_item.def_id.as_local().map(|id| self.tcx().local_def_id_to_hir_id(id))
104                {
105                    if let Some(decl) = self.tcx().hir_fn_decl_by_hir_id(hir_id) {
106                        visitor.visit_fn_decl(decl);
107                    }
108                }
109            }
110            _ => {}
111        }
112
113        let diag = TraitImplDiff {
114            sp,
115            trait_sp,
116            note: (),
117            param_help: ConsiderBorrowingParamHelp { spans: visitor.types.to_vec() },
118            rel_help: visitor.types.is_empty().then_some(RelationshipHelp),
119            expected,
120            found,
121        };
122
123        self.tcx().dcx().emit_err(diag)
124    }
125}
126
127struct TypeParamSpanVisitor<'tcx> {
128    tcx: TyCtxt<'tcx>,
129    types: Vec<Span>,
130}
131
132impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
133    type NestedFilter = nested_filter::OnlyBodies;
134
135    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
136        self.tcx
137    }
138
139    fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) {
140        match arg.kind {
141            hir::TyKind::Ref(_, ref mut_ty) => {
142                // We don't want to suggest looking into borrowing `&T` or `&Self`.
143                if let Some(ambig_ty) = mut_ty.ty.try_as_ambig_ty() {
144                    walk_ty(self, ambig_ty);
145                }
146                return;
147            }
148            hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
149                [segment]
150                    if matches!(
151                        segment.res,
152                        Res::SelfTyParam { .. }
153                            | Res::SelfTyAlias { .. }
154                            | Res::Def(hir::def::DefKind::TyParam, _)
155                    ) =>
156                {
157                    self.types.push(path.span);
158                }
159                _ => {}
160            },
161            _ => {}
162        }
163        hir::intravisit::walk_ty(self, arg);
164    }
165}