]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
Rollup merge of #101159 - tspiteri:track-const-slice-split_at, r=Mark-Simulacrum
[rust.git] / compiler / rustc_infer / src / infer / error_reporting / 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
4 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
5 use crate::infer::error_reporting::note_and_explain_region;
6 use crate::infer::lexical_region_resolve::RegionResolutionError;
7 use crate::infer::{SubregionOrigin, TypeTrace};
8 use crate::traits::ObligationCauseCode;
9 use rustc_data_structures::fx::FxHashSet;
10 use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
11 use rustc_hir as hir;
12 use rustc_hir::intravisit::Visitor;
13 use rustc_middle::ty::TypeVisitor;
14
15 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
16     pub(super) fn try_report_mismatched_static_lifetime(&self) -> Option<ErrorGuaranteed> {
17         let error = self.error.as_ref()?;
18         debug!("try_report_mismatched_static_lifetime {:?}", error);
19
20         let RegionResolutionError::ConcreteFailure(origin, sub, sup) = error.clone() else {
21             return None;
22         };
23         if !sub.is_static() {
24             return None;
25         }
26         let SubregionOrigin::Subtype(box TypeTrace { ref cause, .. }) = origin else {
27             return None;
28         };
29         // If we added a "points at argument expression" obligation, we remove it here, we care
30         // about the original obligation only.
31         let code = match cause.code() {
32             ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => &*parent_code,
33             code => code,
34         };
35         let ObligationCauseCode::MatchImpl(parent, impl_def_id) = code else {
36             return None;
37         };
38         let (ObligationCauseCode::BindingObligation(_, binding_span) | ObligationCauseCode::ExprBindingObligation(_, binding_span, ..))
39             = *parent.code() else {
40             return None;
41         };
42         let mut err = self.tcx().sess.struct_span_err(cause.span, "incompatible lifetime on type");
43         // FIXME: we should point at the lifetime
44         let mut multi_span: MultiSpan = vec![binding_span].into();
45         multi_span.push_span_label(binding_span, "introduces a `'static` lifetime requirement");
46         err.span_note(multi_span, "because this has an unmet lifetime requirement");
47         note_and_explain_region(self.tcx(), &mut err, "", sup, "...", Some(binding_span));
48         if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) {
49             // If an impl is local, then maybe this isn't what they want. Try to
50             // be as helpful as possible with implicit lifetimes.
51
52             // First, let's get the hir self type of the impl
53             let hir::Node::Item(hir::Item {
54                 kind: hir::ItemKind::Impl(hir::Impl { self_ty: impl_self_ty, .. }),
55                 ..
56             }) = impl_node else {
57                 bug!("Node not an impl.");
58             };
59
60             // Next, let's figure out the set of trait objects with implicit static bounds
61             let ty = self.tcx().type_of(*impl_def_id);
62             let mut v = super::static_impl_trait::TraitObjectVisitor(FxHashSet::default());
63             v.visit_ty(ty);
64             let mut traits = vec![];
65             for matching_def_id in v.0 {
66                 let mut hir_v =
67                     super::static_impl_trait::HirTraitObjectVisitor(&mut traits, matching_def_id);
68                 hir_v.visit_ty(&impl_self_ty);
69             }
70
71             if traits.is_empty() {
72                 // If there are no trait object traits to point at, either because
73                 // there aren't trait objects or because none are implicit, then just
74                 // write a single note on the impl itself.
75
76                 let impl_span = self.tcx().def_span(*impl_def_id);
77                 err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
78             } else {
79                 // Otherwise, point at all implicit static lifetimes
80
81                 err.note("...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
82                 for span in &traits {
83                     err.span_note(*span, "this has an implicit `'static` lifetime requirement");
84                     // It would be nice to put this immediately under the above note, but they get
85                     // pushed to the end.
86                     err.span_suggestion_verbose(
87                         span.shrink_to_hi(),
88                         "consider relaxing the implicit `'static` requirement",
89                         " + '_",
90                         Applicability::MaybeIncorrect,
91                     );
92                 }
93             }
94         } else {
95             // Otherwise just point out the impl.
96
97             let impl_span = self.tcx().def_span(*impl_def_id);
98             err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`");
99         }
100         let reported = err.emit();
101         Some(reported)
102     }
103 }