rustc_trait_selection/error_reporting/infer/nice_region_error/
mismatched_static_lifetime.rs

1//! Error Reporting for when the lifetime for a type doesn't match the `impl` selected for a predicate
2//! to hold.
3
4use rustc_data_structures::fx::FxIndexSet;
5use rustc_errors::{ErrorGuaranteed, MultiSpan};
6use rustc_hir as hir;
7use rustc_hir::intravisit::VisitorExt;
8use rustc_middle::bug;
9use rustc_middle::ty::TypeVisitor;
10use tracing::debug;
11
12use crate::error_reporting::infer::nice_region_error::NiceRegionError;
13use crate::errors::{
14    DoesNotOutliveStaticFromImpl, ImplicitStaticLifetimeSubdiag,
15    IntroducesStaticBecauseUnmetLifetimeReq, MismatchedStaticLifetime, note_and_explain,
16};
17use crate::infer::{RegionResolutionError, SubregionOrigin, TypeTrace};
18use crate::traits::ObligationCauseCode;
19
20impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
21    pub(super) fn try_report_mismatched_static_lifetime(&self) -> Option<ErrorGuaranteed> {
22        let error = self.error.as_ref()?;
23        debug!("try_report_mismatched_static_lifetime {:?}", error);
24
25        let RegionResolutionError::ConcreteFailure(origin, sub, sup) = error.clone() else {
26            return None;
27        };
28        if !sub.is_static() {
29            return None;
30        }
31        let SubregionOrigin::Subtype(box TypeTrace { ref cause, .. }) = origin else {
32            return None;
33        };
34        // If we added a "points at argument expression" obligation, we remove it here, we care
35        // about the original obligation only.
36        let ObligationCauseCode::MatchImpl(parent, impl_def_id) = cause.code() else {
37            return None;
38        };
39        let (ObligationCauseCode::WhereClause(_, binding_span)
40        | ObligationCauseCode::WhereClauseInExpr(_, binding_span, ..)) = *parent.code()
41        else {
42            return None;
43        };
44        if binding_span.is_dummy() {
45            return None;
46        }
47
48        // FIXME: we should point at the lifetime
49        let multi_span: MultiSpan = vec![binding_span].into();
50        let multispan_subdiag = IntroducesStaticBecauseUnmetLifetimeReq {
51            unmet_requirements: multi_span,
52            binding_span,
53        };
54
55        let expl = note_and_explain::RegionExplanation::new(
56            self.tcx(),
57            self.generic_param_scope,
58            sup,
59            Some(binding_span),
60            note_and_explain::PrefixKind::Empty,
61            note_and_explain::SuffixKind::Continues,
62        );
63        let mut impl_span = None;
64        let mut implicit_static_lifetimes = Vec::new();
65        if let Some(impl_node) = self.tcx().hir_get_if_local(*impl_def_id) {
66            // If an impl is local, then maybe this isn't what they want. Try to
67            // be as helpful as possible with implicit lifetimes.
68
69            // First, let's get the hir self type of the impl
70            let hir::Node::Item(hir::Item {
71                kind: hir::ItemKind::Impl(hir::Impl { self_ty: impl_self_ty, .. }),
72                ..
73            }) = impl_node
74            else {
75                bug!("Node not an impl.");
76            };
77
78            // Next, let's figure out the set of trait objects with implicit static bounds
79            let ty = self.tcx().type_of(*impl_def_id).instantiate_identity();
80            let mut v = super::static_impl_trait::TraitObjectVisitor(FxIndexSet::default());
81            v.visit_ty(ty);
82            let mut traits = vec![];
83            for matching_def_id in v.0 {
84                let mut hir_v =
85                    super::static_impl_trait::HirTraitObjectVisitor(&mut traits, matching_def_id);
86                hir_v.visit_ty_unambig(impl_self_ty);
87            }
88
89            if traits.is_empty() {
90                // If there are no trait object traits to point at, either because
91                // there aren't trait objects or because none are implicit, then just
92                // write a single note on the impl itself.
93
94                impl_span = Some(self.tcx().def_span(*impl_def_id));
95            } else {
96                // Otherwise, point at all implicit static lifetimes
97
98                for span in &traits {
99                    implicit_static_lifetimes
100                        .push(ImplicitStaticLifetimeSubdiag::Note { span: *span });
101                    // It would be nice to put this immediately under the above note, but they get
102                    // pushed to the end.
103                    implicit_static_lifetimes
104                        .push(ImplicitStaticLifetimeSubdiag::Sugg { span: span.shrink_to_hi() });
105                }
106            }
107        } else {
108            // Otherwise just point out the impl.
109
110            impl_span = Some(self.tcx().def_span(*impl_def_id));
111        }
112        let err = MismatchedStaticLifetime {
113            cause_span: cause.span,
114            unmet_lifetime_reqs: multispan_subdiag,
115            expl,
116            does_not_outlive_static_from_impl: impl_span
117                .map(|span| DoesNotOutliveStaticFromImpl::Spanned { span })
118                .unwrap_or(DoesNotOutliveStaticFromImpl::Unspanned),
119            implicit_static_lifetimes,
120        };
121        let reported = self.tcx().dcx().emit_err(err);
122        Some(reported)
123    }
124}