summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
blob: 1410e2b63b0b87fbfa433ba727a410780b1354de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//! Error Reporting for when the lifetime for a type doesn't match the `impl` selected for a predicate
//! to hold.

use crate::errors::{note_and_explain, IntroducesStaticBecauseUnmetLifetimeReq};
use crate::errors::{ImplNote, MismatchedStaticLifetime, TraitSubdiag};
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::{SubregionOrigin, TypeTrace};
use crate::traits::ObligationCauseCode;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::intravisit::Visitor;
use rustc_middle::ty::TypeVisitor;

impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
    pub(super) fn try_report_mismatched_static_lifetime(&self) -> Option<ErrorGuaranteed> {
        let error = self.error.as_ref()?;
        debug!("try_report_mismatched_static_lifetime {:?}", error);

        let RegionResolutionError::ConcreteFailure(origin, sub, sup) = error.clone() else {
            return None;
        };
        if !sub.is_static() {
            return None;
        }
        let SubregionOrigin::Subtype(box TypeTrace { ref cause, .. }) = origin else {
            return None;
        };
        // If we added a "points at argument expression" obligation, we remove it here, we care
        // about the original obligation only.
        let code = match cause.code() {
            ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => &*parent_code,
            code => code,
        };
        let ObligationCauseCode::MatchImpl(parent, impl_def_id) = code else {
            return None;
        };
        let (ObligationCauseCode::BindingObligation(_, binding_span) | ObligationCauseCode::ExprBindingObligation(_, binding_span, ..))
            = *parent.code() else {
            return None;
        };

        // FIXME: we should point at the lifetime
        let multi_span: MultiSpan = vec![binding_span].into();
        let multispan_subdiag = IntroducesStaticBecauseUnmetLifetimeReq {
            unmet_requirements: multi_span,
            binding_span,
        };

        let expl = note_and_explain::RegionExplanation::new(
            self.tcx(),
            sup,
            Some(binding_span),
            note_and_explain::PrefixKind::Empty,
            note_and_explain::SuffixKind::Continues,
        );
        let mut impl_span = None;
        let mut trait_subdiags = Vec::new();
        if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) {
            // If an impl is local, then maybe this isn't what they want. Try to
            // be as helpful as possible with implicit lifetimes.

            // First, let's get the hir self type of the impl
            let hir::Node::Item(hir::Item {
                kind: hir::ItemKind::Impl(hir::Impl { self_ty: impl_self_ty, .. }),
                ..
            }) = impl_node else {
                bug!("Node not an impl.");
            };

            // Next, let's figure out the set of trait objects with implicit static bounds
            let ty = self.tcx().type_of(*impl_def_id);
            let mut v = super::static_impl_trait::TraitObjectVisitor(FxHashSet::default());
            v.visit_ty(ty);
            let mut traits = vec![];
            for matching_def_id in v.0 {
                let mut hir_v =
                    super::static_impl_trait::HirTraitObjectVisitor(&mut traits, matching_def_id);
                hir_v.visit_ty(&impl_self_ty);
            }

            if traits.is_empty() {
                // If there are no trait object traits to point at, either because
                // there aren't trait objects or because none are implicit, then just
                // write a single note on the impl itself.

                impl_span = Some(self.tcx().def_span(*impl_def_id));
            } else {
                // Otherwise, point at all implicit static lifetimes

                for span in &traits {
                    trait_subdiags.push(TraitSubdiag::Note { span: *span });
                    // It would be nice to put this immediately under the above note, but they get
                    // pushed to the end.
                    trait_subdiags.push(TraitSubdiag::Sugg { span: span.shrink_to_hi() });
                }
            }
        } else {
            // Otherwise just point out the impl.

            impl_span = Some(self.tcx().def_span(*impl_def_id));
        }
        let err = MismatchedStaticLifetime {
            cause_span: cause.span,
            unmet_lifetime_reqs: multispan_subdiag,
            expl,
            impl_note: ImplNote { impl_span },
            trait_subdiags,
        };
        let reported = self.tcx().sess.emit_err(err);
        Some(reported)
    }
}